Allow wildcards in the source file section of the configuration. The script evaluates wildcards and adds matching source files automatically.
415 lines
14 KiB
Tcl
415 lines
14 KiB
Tcl
package require json
|
|
|
|
# Helper procedure for formatted messages
|
|
proc _info {message} {
|
|
puts [format "INFO: %s" $message]
|
|
}
|
|
proc _warn {message} {
|
|
puts [format "WARN: %s" $message]
|
|
}
|
|
proc _error {message details} {
|
|
error [format "ERROR: %s. Details: %s" $message $details]
|
|
}
|
|
|
|
# Helper procedure to create hardware platform
|
|
proc _prepare_platform {hw_file platform_name is_vitis} {
|
|
if {![file exists $hw_file]} {
|
|
_error "Hardware design file does not exist" $hw_file
|
|
}
|
|
_info "Creating hardware platform: $platform_name"
|
|
if {$is_vitis} {
|
|
platform create -name $platform_name -hw $hw_file
|
|
_info "Platform '$platform_name' created successfully for Vitis."
|
|
} else {
|
|
sdk createhw -name $platform_name -hwspec $hw_file
|
|
_info "Hardware platform '$platform_name' created successfully for Xilinx SDK."
|
|
}
|
|
}
|
|
|
|
# Helper procedure for BSP configuration
|
|
proc _configure_bsp {bsp_name bsp_config platform_name is_vitis} {
|
|
set cpu [dict get $bsp_config target_cpu]
|
|
set os [dict get $bsp_config os]
|
|
|
|
# Create Domain/BSP
|
|
_info "Creating BSP: $bsp_name for CPU: $cpu and OS: $os"
|
|
if {$is_vitis} {
|
|
platform active $platform_name
|
|
domain create -name $bsp_name -os $os -proc $cpu
|
|
domain active $bsp_name
|
|
_info "BSP '$bsp_name' created for Vitis."
|
|
} else {
|
|
sdk createbsp -name $bsp_name -hwproject $platform_name -proc $cpu -os $os
|
|
_info "BSP '$bsp_name' created for Xilinx SDK."
|
|
}
|
|
|
|
# Apply BSP library configurations if they exist
|
|
if {[dict exists $bsp_config libs]} {
|
|
_info "Configuring BSP libraries..."
|
|
dict for {lib_name lib_info} [dict get $bsp_config libs] {
|
|
if {$is_vitis} {
|
|
bsp setlib -name $lib_name -ver [dict get $lib_info version]
|
|
} else {
|
|
setlib -bsp $bsp_name -lib $lib_name -ver [dict get $lib_info version]
|
|
}
|
|
_info "Applied library '$lib_name' version '[dict get $lib_info version]' for BSP '$bsp_name'."
|
|
if {[dict exists $lib_info config]} {
|
|
dict for {param value} [dict get $lib_info config] {
|
|
if {$is_vitis} {
|
|
bsp config $param $value
|
|
} else {
|
|
configbsp -bsp $bsp_name $param $value
|
|
}
|
|
_info "Configured library '$lib_name': $param = $value"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Apply BSP configurations if they exist
|
|
if {[dict exists $bsp_config config]} {
|
|
_info "Configuring BSP options..."
|
|
dict for {param value} [dict get $bsp_config config] {
|
|
if {$is_vitis} {
|
|
bsp config $param $value
|
|
} else {
|
|
configbsp -bsp $bsp_name $param $value
|
|
}
|
|
_info "Applied BSP configuration: $param = $value for $bsp_name"
|
|
}
|
|
}
|
|
|
|
if {$is_vitis} {
|
|
bsp regenerate
|
|
} else {
|
|
regenbsp -bsp $bsp_name
|
|
projects -build -type bsp -name $bsp_name
|
|
}
|
|
_info "BSP '$bsp_name' successfully configured and regenerated."
|
|
return $bsp_name
|
|
}
|
|
|
|
# Helper procedure to handle source files: link or copy based on LINK_SRCS
|
|
proc _handle_sources {app_name sources} {
|
|
# Check environment variable LINK_SRCS
|
|
set link_srcs "y"
|
|
if {[info exists ::env(LINK_SRCS)]} {
|
|
set link_srcs $::env(LINK_SRCS)
|
|
}
|
|
|
|
foreach source_file $sources {
|
|
# Expand wildcards
|
|
set expanded_sources [glob -nocomplain -directory $::root $source_file]
|
|
if {[llength $expanded_sources] == 0} {
|
|
_error "Source file not found" "No file or directory matches $source_file"
|
|
}
|
|
# Hanle each expanded source
|
|
foreach eval_source $expanded_sources {
|
|
set relative_source [string range $eval_source [expr [string length $::root] + 1] end]
|
|
set target_path [file join $::ws $app_name $relative_source]
|
|
|
|
# Ensure the target directory exists
|
|
set target_dir [file dirname $target_path]
|
|
if {![file exists $target_dir]} {
|
|
file mkdir $target_dir
|
|
_info "Created directory: $target_dir"
|
|
}
|
|
|
|
# Delete existing symbolic link or file if it exists
|
|
if {[file exists $target_path]} {
|
|
file delete -force $target_path
|
|
_warn "Deleted existing link or file: $target_path"
|
|
}
|
|
|
|
# Handle source based on the value of LINK_SRCS
|
|
switch $link_srcs {
|
|
"y" {
|
|
# Create symbolic link
|
|
file link -symbolic $target_path $eval_source
|
|
_info "Created symbolic link: $target_path -> $eval_source"
|
|
}
|
|
"n" {
|
|
# Copy the source file
|
|
file copy $eval_source $target_path
|
|
_info "Copied source file: $eval_source to $target_path"
|
|
}
|
|
default {
|
|
_error "Unknown value for LINK_SRCS: ${link_srcs}."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc _update_app_mem_layout {app_name mem_layout} {
|
|
|
|
# Update heap and stack sizes in linker script if specified
|
|
set lscript_path "$::ws/$app_name/src/lscript.ld"
|
|
if {[file exists $lscript_path]} {
|
|
set file_content {}
|
|
set file_id [open $lscript_path r]
|
|
while {[gets $file_id line] >= 0} {
|
|
if {[regexp {^_HEAP_SIZE =} $line] && [dict exists $mem_layout heap_size]} {
|
|
set heap_size [dict get $mem_layout heap_size]
|
|
if {$heap_size ne ""} {
|
|
set line "_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : $heap_size;"
|
|
_info "Updating _HEAP_SIZE in linker script to $heap_size"
|
|
} else {
|
|
_warn "Empty `heap_size` config, _HEAP_SIZE not updated."
|
|
}
|
|
} elseif {[regexp {^_STACK_SIZE =} $line] && [dict exists $mem_layout stack_size]} {
|
|
set stack_size [dict get $mem_layout stack_size]
|
|
if {$stack_size ne ""} {
|
|
set line "_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : $stack_size;"
|
|
_info "Updating _STACK_SIZE in linker script to $stack_size"
|
|
} else {
|
|
_warn "Empty `stack_size` config, _STACK_SIZE not updated."
|
|
}
|
|
}
|
|
lappend file_content $line
|
|
}
|
|
close $file_id
|
|
|
|
set file_id [open $lscript_path w]
|
|
puts $file_id [join $file_content \n]
|
|
close $file_id
|
|
} else {
|
|
_warn "Linker script $lscript_path not found for application: $app_name"
|
|
}
|
|
}
|
|
|
|
proc _update_app_build_config {app_name build_type build_config is_vitis} {
|
|
set build_types {"debug" "release"}
|
|
if {[lsearch $build_types $build_type] == -1} {
|
|
_error "Invalid config type: $build_type" "available types: $build_types"
|
|
}
|
|
|
|
set cmd [list]
|
|
if {$is_vitis} {
|
|
lappend cmd app config -name
|
|
} else {
|
|
lappend cmd sdk configapp -app
|
|
}
|
|
|
|
_info "Setting build configuration for '$app_name' as $build_type."
|
|
eval $cmd $app_name -set build-config $build_type
|
|
|
|
dict for {param value} $build_config {
|
|
switch -exact -- $param {
|
|
"include-path" -
|
|
"library-search-path" {
|
|
foreach path $value {
|
|
set path_str [format "\"\${workspace_loc:/%s/%s}\"" $app_name $path]
|
|
eval $cmd $app_name $param [list $path_str]
|
|
_info "Append $param: $path for $app_name."
|
|
}
|
|
}
|
|
"define-compiler-symbols" -
|
|
"undef-compiler-symbols" -
|
|
"libraries" {
|
|
foreach item $value {
|
|
eval $cmd $app_name $param $item
|
|
_info "Append parameter $param: $item for $app_name."
|
|
}
|
|
}
|
|
"assembler-flags" -
|
|
"compiler-misc" -
|
|
"compiler-optimization" -
|
|
"linker-misc" -
|
|
"linker-script" {
|
|
if {$value ne ""} {
|
|
eval $cmd $app_name -set $param $value
|
|
_info "Set $param: $value for $app_name."
|
|
}
|
|
}
|
|
default {
|
|
_error "Unsupported app build-config option" $param
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Helper procedure for application configuration
|
|
proc _create_app {app_name app_config platform_name is_vitis} {
|
|
set cpu [dict get $app_config target_cpu]
|
|
set os [dict get $app_config os]
|
|
set lang [dict get $app_config language]
|
|
set sources [dict get $app_config sources]
|
|
set bsp_name "${os}_${cpu}"
|
|
|
|
# Configure BSP/Domain for application
|
|
if {[dict exists $app_config bsp] && [dict get $app_config bsp] ne ""} {
|
|
set bsp_name [dict get $app_config bsp]
|
|
} else {
|
|
set bsp_config [dict create]
|
|
set bsp_config [dict set bsp_config target_cpu $cpu]
|
|
set bsp_config [dict set bsp_config os $os]
|
|
if {[dict exists $app_config bsp_lib]} {
|
|
set bsp_lib [dict get $app_config bsp_lib]
|
|
set bsp_config [dict merge $bsp_config [dict create libs $bsp_lib]]
|
|
}
|
|
if {[dict exists $app_config bsp_config]} {
|
|
set bsp_cfg [dict get $app_config bsp_config]
|
|
set bsp_config [dict merge $bsp_config [dict create config $bsp_cfg]]
|
|
}
|
|
_configure_bsp $bsp_name $bsp_config $platform_name $is_vitis
|
|
}
|
|
|
|
# Create application
|
|
_info "Creating application: $app_name"
|
|
if {$is_vitis} {
|
|
app create -name $app_name \
|
|
-platform $platform_name \
|
|
-domain $bsp_name \
|
|
-proc $cpu \
|
|
-os $os \
|
|
-lang $lang \
|
|
-sysproj $::project_name \
|
|
-template "Empty Application($lang)"
|
|
_info "Application '$app_name' created for Vitis."
|
|
} else {
|
|
sdk createapp -name $app_name \
|
|
-hwproject $platform_name \
|
|
-bsp $bsp_name \
|
|
-proc $cpu \
|
|
-os $os \
|
|
-lang $lang \
|
|
-app "Empty Application"
|
|
_info "Application '$app_name' created for Xilinx SDK."
|
|
}
|
|
|
|
# Handle source files if present
|
|
if {[llength $sources] > 0} {
|
|
_info "Handling sources for application: $app_name"
|
|
_handle_sources $app_name $sources
|
|
} else {
|
|
_warn "No source files specified for application: $app_name"
|
|
}
|
|
|
|
# Configure application if additional configs exist
|
|
_info "Configuring application: $app_name"
|
|
if {[dict exists $app_config build_config]} {
|
|
dict for {build_type build_config} [dict get $app_config build_config] {
|
|
_update_app_build_config $app_name $build_type $build_config $is_vitis
|
|
}
|
|
}
|
|
|
|
# Update memory layout in linker script if specified
|
|
_info "Updating memory layout for application: $app_name"
|
|
if {[dict exists $app_config mem_layout]} {
|
|
set mem_layout [dict get $app_config mem_layout]
|
|
_update_app_mem_layout $app_name $mem_layout
|
|
}
|
|
}
|
|
|
|
# Apply FSBL patches if specified
|
|
# TODO:
|
|
proc _apply_fsbl_patches {patches} {
|
|
_info "Applying FSBL patches."
|
|
dict for {target_file patch_file} $patches {
|
|
set target_path "$::ws/fsbl/src/$target_file"
|
|
set patch_path "$::root/$patch_file"
|
|
|
|
file copy -force $patch_path $target_path
|
|
if {[file exists $patch_path]} {
|
|
_info "Patched $target_file with $patch_file"
|
|
} else {
|
|
_warn "FSBL patch file $patch_path not found, new file $patch_file "
|
|
}
|
|
}
|
|
}
|
|
|
|
# Main procedures
|
|
proc create_project {} {
|
|
cd $::ws
|
|
setws $::ws
|
|
_info "Workspace set to $::ws."
|
|
|
|
set is_vitis [expr {[string first ".hdf" $::hw_file] == -1}]
|
|
set platform_name "${::project_name}_platform"
|
|
|
|
# Prepare hardware platform
|
|
_prepare_platform $::hw_file $platform_name $is_vitis
|
|
|
|
# Process each bsp
|
|
if {[dict exists $::config bsps]} {
|
|
dict for {bsp_name bsp_config} [dict get $::config bsps] {
|
|
_configure_bsp $bsp_name $bsp_config $platform_name $is_vitis
|
|
}
|
|
}
|
|
|
|
# Process each application
|
|
dict for {app_name app_config} [dict get $::config apps] {
|
|
_create_app $app_name $app_config $platform_name $is_vitis
|
|
}
|
|
}
|
|
|
|
proc build_project {} {
|
|
setws $::ws
|
|
set is_vitis [expr {[string first ".hdf" $::hw_file] == -1}]
|
|
if {$is_vitis} {
|
|
# paltform file can be deleted by clean operation ahead
|
|
platform active ${::project_name}_platform
|
|
platform generate
|
|
}
|
|
|
|
# Determine build type from environment
|
|
set build_type "debug"
|
|
if {[info exists ::env(RELEASE)] && $::env(RELEASE) == "y"} {
|
|
set build_type "release"
|
|
}
|
|
_info "Build type: $build_type"
|
|
|
|
dict for {app_name app_config} [dict get $::config apps] {
|
|
_info "Building application: $app_name"
|
|
if {$is_vitis} {
|
|
app config -name $app_name -set build-config $build_type
|
|
app build -name $app_name
|
|
_info "Application '$app_name' built for Vitis."
|
|
} else {
|
|
sdk configapp -app $app_name -set build-config $build_type
|
|
projects -build -type app -name $app_name
|
|
_info "Application '$app_name' built for Xilinx SDK."
|
|
}
|
|
}
|
|
}
|
|
|
|
proc clean_project {} {
|
|
setws $::ws
|
|
_info "Cleaning project in workspace: $::ws."
|
|
|
|
set is_vitis [expr {[string first ".hdf" $::hw_file] == -1}]
|
|
|
|
dict for {app_name app_config} [dict get $::config apps] {
|
|
_info "Cleaning application: $app_name"
|
|
if {$is_vitis} {
|
|
app clean -name $app_name
|
|
} else {
|
|
projects -clean -type app -name $app_name
|
|
}
|
|
_info "Application '$app_name' cleaned."
|
|
}
|
|
}
|
|
|
|
# Main execution
|
|
set function [lindex $argv 0]
|
|
set config_file [lindex $argv 1]
|
|
set ws [file normalize [lindex $argv 2]]
|
|
_info "Working at $ws"
|
|
|
|
# Load and parse configuration
|
|
set config_file_id [open $config_file r]
|
|
set config_data [read $config_file_id]
|
|
close $config_file_id
|
|
set root [file dirname [file normalize $config_file]]
|
|
set config [json::json2dict $config_data]
|
|
set project_name [dict get $config project_name]
|
|
set hw_file [file normalize [file join [file dirname $config_file] [dict get $config hw_design]]]
|
|
|
|
_info "Starting process: $function"
|
|
_info "Project name: $project_name"
|
|
_info "Hardware design file: $hw_file"
|
|
|
|
# Execute requested function
|
|
$function
|
|
_info "Process $function completed." |