Compare commits

..
32 Commits
Author SHA1 Message Date
Gatsby d13f6cb8b3 refactor(platform/xilinx): replace symbolic links with hard links for better compatibility
- Replaced symbolic links with hard links in the Vitis project source management.
- Symbolic links often cause reference issues during debugging in Xilinx Vitis.
- This change improves source visibility and debugger integration.
2025-06-13 12:24:45 +08:00
Gatsby 0eb4535dc8 bug(platform/xilinx): fix variable typo 2025-05-09 22:43:58 +08:00
Gatsby 94c8d59201 chore(platform/xilinx): add variable checks and clean up Makefile 2025-05-09 22:30:16 +08:00
Gatsby 5fd695266f refactor(make): reorganize targets and improve locking mechanism
1.	Introduce a “project lock” mechanism alongside the existing “build lock”; the lock file is now generated within the platform-specific Makefile.
2.	Set `project` as the default Makefile goal for consistency.
3.	Remove the `standalone` target to improve compatibility, especially when invoked via `make -f`.
4.	Simplify target dependencies for better maintainability and clarity.
2025-05-09 22:27:52 +08:00
Gatsby 698e123a26 chore: refine common commands 2025-05-09 22:22:40 +08:00
Gatsby Van 751071d670 refactor(platform/xilinx): use tcl command to create links eliminating the need for administrator privileges on Windows 2025-02-24 01:40:14 +08:00
Gatsby Van af260c1610 docs(platform/xilinx): update path descriptions in documentation 2024-11-06 00:33:15 +08:00
Gatsby Van caa636018b refactor: make paths relative to current working directory
- Allows configuration files to be placed in separate folders, with paths in config files now relative to the config file's location.
- Added `cd /d "%~dp0"` at the beginning of the `.bat` template to ensure paths are based on the script's location, enhancing portability and consistency.
2024-11-06 00:32:04 +08:00
Gatsby Van 94aea3524e chore: fix typo 2024-11-05 23:49:32 +08:00
Gatsby Van 906df8b40a fix(platform/xilinx): correct option from -template to -app in Xilinx SDK setup
Replaces the incorrect `-template` option with `-app` for proper Xilinx SDK project configuration, resolving an issue introduced in the last commit.
2024-11-04 20:36:33 +08:00
Gatsby Van 38d3fd5667 chore(makefile): add @ to silence specific print commands 2024-11-04 20:36:33 +08:00
Gatsby Van eb3ca273b4 refactor(platform/xilinx): strengthen parameter validation 2024-11-04 20:36:33 +08:00
Gatsby Van af92cd0a53 feat(platform/xilinx): add support for specifying application template 2024-11-04 20:36:33 +08:00
Gatsby Van 61da61b28e refactor(platform/xilinx): modify default BSP/Domain names to reduce conflicts 2024-11-04 20:36:33 +08:00
Gatsby Van c042d2c391 fix(platform/xilinx): fix(platform/xilinx): ensure domain is generated post-creation 2024-11-04 20:36:33 +08:00
Gatsby 1ccae2ebed docs: add common issue regarding symbolic links on Windows 2024-11-04 20:36:22 +08:00
Gatsby ead5e96c13 refactor(platform/xilinx): improve print message output 2024-10-29 14:30:07 +08:00
Gatsby 47bb9119dd fix(platform/xilinx): fallback to mklink for file symlink creation on Windows 2024-10-29 14:26:26 +08:00
Gatsby 20c8751540 fix: correct script name in .bat template 2024-10-29 14:17:46 +08:00
Gatsby 5cfc64b518 fix(platform/xilinx): reset %ERRORLEVEL% after user input to prevent errors from empty input 2024-10-29 14:16:44 +08:00
Gatsby Van 3ada35e863 docs(platform/xilinx): add description for sources section, fix typos
Added a description of the `sources` field, detailing its use of relative paths and wildcard support. Fixed minor typos for clarity.
2024-10-28 17:39:46 +08:00
Gatsby Van df5cc85fa7 feat(platform/xilinx): enable wildcard support in source file configuration
Allow wildcards in the source file section of the configuration. The script evaluates wildcards and adds matching source files automatically.
2024-10-28 17:24:43 +08:00
Gatsby Van 72c5619f59 fix(platform/xilinx): set library-search-path as workspace-relative path 2024-10-28 17:21:28 +08:00
Gatsby Van f9a2a2e0d9 docs: add 'Common Issues' section to README with steps for triggering index update in Vitis. 2024-10-28 13:57:10 +08:00
Gatsby Van 41cca8c4e1 fix(platform/xilinx): set the include dir as a workspace dir to ensure proper indexer functionality 2024-10-28 11:23:14 +08:00
Gatsby Van c467f2fa0b feat(platform/xilinx): add a command interface to acquire tool installation path 2024-10-27 22:41:56 +08:00
Gatsby Van 5467577b07 docs(platform/xilinx): fix typo 2024-10-27 22:32:59 +08:00
Gatsby Van 9955c87eaf docs(platform/xilinx): correct format, move minium configuration up 2024-10-27 22:32:05 +08:00
Gatsby 34048913c6 fix(platform/xilinx): make bsps an optional section. 2024-10-27 12:00:54 +08:00
Gatsby d68aee0411 docs: update contribution section and fix typo. 2024-10-26 01:07:30 +08:00
Gatsby de4130ff88 Merge initial README 2024-10-26 00:51:20 +08:00
Gatsby b93e7f85a4 Initial commit 2024-10-26 00:49:32 +08:00
13 changed files with 1336 additions and 0 deletions
+172
View File
@@ -1,2 +1,174 @@
# embedded-autobuild
`embedded-autobuild` 是一个实用脚本库,旨在简化从源码构建目标 IDE 工程的流程。该脚本库通过 `JSON` 文件管理工程配置,并使用 IDE 的命令行接口快速实现项目的重建与管理,减少手动配置的繁琐步骤。
## 特性
- 使用 JSON 文件保存硬件设计、应用程序配置、BSP 设置等项目配置。
- 支持多个 IDE 工具链,便于多平台开发或切换开发环境。
- 支持自动化构建,确保在多次迭代开发中保持一致性。
## 支持的开发工具
本项目目前支持以下 Xilinx 工具链版本:
- **Xilinx SDK** 版本:`2017.1` ~ `2019.2`
- **Xilinx Vitis** 版本:`2019.2` ~ `2023.1`
- **Xilinx Vitis Classic** 版本:`2023.2` 及以上
## 工程配置
在使用脚本前,请参考以下文档配置对应平台:
- [Xilinx 平台配置指南](./platform/xilinx/HOWTO.md)
## 项目结构
- `platform/` - 包含各平台构建工具脚本
- `generic_variables.mk` - 使用 `make` 工具构建时的基本变量声明
- `generic.mk` - 提供若干实用构建目标
- `template.mk` - 基于 `make` 的构建模板
- `template.bat` - 基于 Windows 批处理文件的构建模板
## 快速开始
1. **将项目添加为 `submodule`**
在目标项目的根目录下运行以下命令,将 `embedded-autobuild` 项目作为 `scripts` 文件夹的子模块:
```shell
git submodule add https://git.gatsby.icu/gatsby/embedded-autobuild.git scripts
```
2. **初始化并更新子模块**
如果已经有子模块配置,请使用以下命令初始化并更新子模块:
```shell
git submodule update --init --recursive
```
若需更新子模块,使用以下命令:
```shell
git submodule update --remote
```
3. **添加配置文件**
将对应平台的配置模板文件拷贝到工程根目录:
```shell
cp ./scripts/platform/<your_platform>/template.json ./config.json
```
**请参照对应平台[配置说明](#工程配置),根据实际需要修改配置文件**。
4. **添加构建脚本**
1. 如果使用 `make` 进行工程构建,可以基于 [`template.mk`](./template.mk) 编写自己的 Makefile:
```shell
cp ./scripts/template.mk Makefile
```
其内容如下,只需指定 `PLATFORM` 和 `CONFIG_FILE` 即可。默认在当前工作路径的 `build` 文件夹下构建工程:
```makefile
include scripts/generic_variables.mk
PLATFORM := <your_platform> # eg. xilinx
CONFIG_FILE := <config_file> #eg. $(PROJECT)/config.json
include scripts/generic.mk
```
你还可以根据需求追加更多自定义构建目标。默认的构建目标如下:
- `all`: 构建并编译配置文件中所有的工程
- `project`: 仅构建工程
- `build`: 编译所有已配置工程
- `sdkopen`: 打开对应开发工具
- `clean`: 清除当前编译结果
- `reset`: 删除所有已构建工程
2. 对于 Windows 系统,还支持通过批处理文件或 PowerShell 脚本实现自动化构建。可基于 [`template.bat`](./template.bat) 编写自己的批处理脚本:
```shell
cp ./scripts/template.bat make.bat
```
该模板内容如下,需指定以下参数:
- `platform`: 使用的平台
- `pltform_ver`: 平台工具版本
- `work_dir`: 工作目录(即构建工程存储的目录)
- `config`: 配置文件
- `tools_dir`: 平台工具脚本目录
```bat
@echo off
set "platform=xilinx"
set "pltform_ver=2019.1"
set "work_dir=%~dp0build"
set "config=%~dp0config.json"
set "tools_dir=%~dp0scripts\platform\%platform%"
REM Set up environment
call "%tools_dir%\setenv.bat" "%pltform_ver%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to initialize environment.
pause >nul
exit /b 1
)
REM Build project
call "%tools_dir%\build.bat" "%config%" "%work_dir%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to build project.
pause >nul
exit /b 1
)
REM Launch SDK
call "%tools_dir%\launch.bat" "%pltform_ver%" "%work_dir%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to launch SDK.
pause >nul
exit /b 1
)
exit /b 0
```
其中 `%~dp0` 表示当前 `.bat` 文件所在目录。上述模板配置假设配置文件和相关工具脚本与 `.bat` 在同一目录,并在该目录下的 `build` 文件夹中创建工程。该脚本实现了自动创建工程并完成相关配置最后加载对应 IDE 的功能。
## 常见问题
1. 在 Xilinx Vitis 中打开构建的工程后,点击符号时可能无法跳转,并且在 IDE 左下角会显示如下错误信息:
```plaintext
Could not find symbol 'XXXX' in index
```
这是因为源文件在导入时被直接链接或复制到了工程目录中,未触发 C++ Indexer 更新索引。此外,新版本的 Vitis 没有直接的命令或 UI 选项来重建或更新索引。最简单的解决方法是随意打开一个源文件,在任意行末输入一个空格并保存。IDE 会自动删除该空格,不会对源文件造成任何更改,但此操作可触发索引的自动更新。
2. 在 Windows 上运行 `.bat` 构建脚本时可能会出现以下错误:
```plaintext
Failed to create file symbolic link using mklink: 你没有足够的权限执行此操作。
```
这是因为 `tcl` 在 Windows 上只能为文件夹创建符号链接,无法直接为文件创建链接。为文件创建符号链接需要使用 `mklink` 命令,该命令要求管理员权限。解决方法是以管理员身份运行 `.bat` 脚本。
## 待办事项
- [x] 支持 Xilinx SDK 的 XSCT 接口
- [x] 支持 Xilinx Vitis 的 XSCT 接口
- [ ] 增加对 Xilinx Vitis Python API 的支持
- [ ] 完善 Xilinx 工具下 FSBL 补丁的功能
- [ ] 支持 IAR 工具链
## 贡献指南
如果您对该项目有任何改进意见或功能需求,欢迎提交 issue 或 pull request,commit 格式请参考 [Angular convention](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit).
+84
View File
@@ -0,0 +1,84 @@
ifeq ($(VERBOSE),y)
else
HIDE = > /dev/zero
.SILENT:
endif
TIMESTAMP = $(shell date +"%T")
cmd_copy = cp -a $(1) $(2)
cmd_link = ln -sfr $(1) $(2)
cmd_remove = rm -rf $(1)
cmd_mkdir = mkdir -p $(1)
cmd_cat = cat $(1) 2>/dev/null
cmd_print_lines = echo $(1) | tr ' ' '\n'
color_green = \033[32m$(1)\033[0m
log = @printf "$(call color_green,[$(TIMESTAMP)]) %s\n" "$(1)"
show_build_type = $(call log,Building for $(call green,$(1)))
check-var = $(if $(strip $($(1))),,$(error [ERROR] Missing required variable: $(1)))
check_command = $(shell which $(1) > /dev/null 2>&1 && echo y || echo n)
$(call check-var,PROJECT)
$(call check-var,PLATFORM)
$(call check-var,BUILD_DIR)
$(call check-var,CONFIG_FILE)
$(call check-var,LINK_SRCS)
ifndef SCRIPT_DIR
CURRENT_FILE := $(lastword $(MAKEFILE_LIST))
CURRENT_DIR := $(patsubst %/,%,$(dir $(CURRENT_FILE)))
SCRIPT_DIR := $(CURRENT_DIR)
endif
ifeq ($(strip $(LINK_SRCS)),y)
update_files = $(call cmd_link,$(1),$(2))
update_dir = $(call cmd_link,$(1),$(2))
ACTION = Linking
else
update_files = $(call cmd_copy,$(1),$(dir $(2)))
update_dir = $(call cmd_copy,$(1),$(2))
ACTION = Copying
endif
#------------------------------------------------------------------------------
# COMMON INITIALIZATION
#------------------------------------------------------------------------------
PLATFORM_TOOLS = $(SCRIPT_DIR)/platform/$(PLATFORM)
BUILD_LOCK = $(BUILD_DIR)/.build.lock
PROJECT_LOCK = $(BUILD_DIR)/.project.lock
ifeq ('xilinx', '$(PLATFORM)')
include $(PLATFORM_TOOLS)/xilinx.mk
endif
#------------------------------------------------------------------------------
# Generic Goals
#------------------------------------------------------------------------------
PHONY := clean reset project build sdkopen
.DEFAULT_GOAL := project
# Create project using corresponding SDK
project: $(PLATFORM)_project
# Build project using corresponding compiler
build: project $(PLATFORM)_sdkbuild
# Open the project using the corresponding SDK
sdkopen: project $(PLATFORM)_sdkopen
# Remove build artefacts
ifneq ($(wildcard $(BUILD_LOCK)),)
clean: $(PLATFORM)_sdkclean
else
clean: reset
endif
# Remove the whole build directory
reset: $(PLATFORM)_reset
@$(call log,[Delete] $(BUILD_DIR))
@$(call cmd_remove,$(BUILD_DIR))
.PHONY: $(PHONY)
+9
View File
@@ -0,0 +1,9 @@
#Variables needed by makefile
PROJECT ?= $(realpath .)
BUILD_DIR ?= $(PROJECT)/build
CONFIG_FILE ?= $(PROJECT)/config.json
SCRIPT_DIR ?= $(PROJECT)/scripts
# By default link sources into the build directory of the project.
# This way all needed files will be in one place and they can be tracked on git
LINK_SRCS ?= y
+243
View File
@@ -0,0 +1,243 @@
# Xilinx 平台配置指南 (HOWTO)
## 目录结构说明
- **build.bat**: 用于在 Windows 系统上运行的批处理脚本,负责自动化构建整个项目;
- **launch.bat**: 用于启动 Xilinx SDK 或 Vitis 的批处理脚本,适用于在 Windows 系统上打开开发环境,加载并查看生成的工程;
- **setenv.bat**: 运行环境配置脚本,用于在 Windows 系统中设置 Xilinx 开发工具的环境变量,通常在构建或启动项目前运行;
- **template.gitignore**: 针对 Xilinx 工具的 `.gitignore` 模板文件,用户可以将其内容复制到实际的 `.gitignore` 文件中;
- **template.json**: 项目的 JSON 配置模板文件,定义了工程的基本配置,具体配置参数请参考[配置文件说明](#配置文件说明);
- **util.tcl**: 包含一组通用工具命令的 TCL 脚本,用于辅助自动化构建过程。此文件在构建过程中被调用,用于与开发工具交互执行 Xilinx 工具相关的特定操作;
- **xilinx.mk**: 被 [`generic.mk`](../../generic.mk) 定义了 Xilinx 平台的特定的编译规则;
## 配置文件说明
配置文件用于定义 Xilinx 平台项目的构建参数、应用配置和库依赖关系等信息,以便于在 `embedded-autobuild` 项目中自动化生成工程。以下为最小化完整配置示例,包含了所有必填字段,可作为基础配置参考。
```json
{
"project_name": "demo",
"version": "0.0.0",
"hw_design": "demo_v0.0.0.hdf",
"apps": {
"demo_app": {
"sources": ["source/"],
"target_cpu": "ps7_cortexa9_0",
"os": "standalone",
"language": "C",
}
}
}
```
如需添加更多配置请详细阅读后续 Xilinx 配置文件各部分的详细说明。
> **注**:以下针对字段的解释中 **加粗** 字段为必须参数,*斜体* 标注的字段为可选参数,可选参数不填写则使用对应 IDE 的默认配置。
### 基本字段
- **project_name**: 项目名称,例如 `"demo"`。
- **version**: 项目版本,例如 `"0.0.0"`。
- **hw_design**: 硬件设计文件(`.hdf` 或 `.xsa` 文件)路径(相对档案工作路径),例如 `"demo_v0.0.0.hdf"`。
### *fsbl_patch* (TODO)
用于配置 `FSBL` (First Stage Bootloader) 的补丁文件。可以包含多个补丁文件以满足自定义的硬件启动需求。
```json
"fsbl_patch": {
"<patch_target0>": "<patch_file0>",
"<patch_target1>": "<patch_file1>"
}
```
其基本格式为 `<patch_target>: <patch_file>`,`<patch_target>` 是 FSBL 中需要被替换的文件,`<patch_file>` 为准备好的替换补丁文件。
### *bsps*
该字段用于定义 BSP 或者 Domain 的配置,支持多个 BSP/Domain 配置。
```json
"bsps": {
"<bsp_name>": {
"os": "<os_type>",
"target_cpu": "<cpu_id>",
"libs": {
"<lib_name>": {
"version": "<lib_version>",
"config": {
"<parameter0>": "<value0>",
"<parameter1>": "<value1>"
...
}
}
...
},
"config": {
"<parameter0>": "<value0>",
"<parameter1>": "<value1>"
...
}
}
...
}
```
- **os**: 操作系统类型,支持的类型有 `standalone`,`freetos`,`linux`[^1];
- **target_cpu**: 目标 CPU[^2],例如 "ps7_cortexa9_0" 表示 Zynq-7000 系列的 ARM Cortex-A9 核;
-*libs*: 必要的库及其版本配置[^1],该配置项下可包含多个 `lib` 配置,默认不添加任何 `lib`;
- **version**: `lib` 版本 [^1];
- *config*: 其他具体 `lib` 设置[^1],不填写则使用 IDE 默认配置;
-*config*: 其他具体 BSP/Domain 设置[^1],不填写则使用 IDE 默认配置;
以下配置添加了一个名为 "standalone" 的 BSP/Domain 工程,添加了 `xilffs` 和 `xilrsa` 两个 `lib,其中` `xilffs` 启用了长文件名(use_lfn)以及exFAT(enable_exfat)支持,并设置了标准输入输出为 `ps7_coresight_comp_0`,sleep 计数器使用 `ps7_globaltimer_0`.
```json
"bsps": {
"standalone": {
"os": "standalone",
"target_cpu": "ps7_cortexa9_0",
"libs": {
"xilffs": {
"version": "4.1",
"config": {
"use_lfn": true,
"enable_exfat": true
}
},
"xilrsa": {
"version": "1.5"
}
},
"config": {
"stdin": "ps7_coresight_comp_0",
"stdout": "ps7_coresight_comp_0",
"sleep_timer": "ps7_globaltimer_0"
}
}
}
```
### apps
该字段定义应用的具体构建配置,包括目标 CPU、操作系统、内存布局等,编译参数等。
```json
"apps": {
"<app_name>": {
"sources": ["dir0", "dir1"],
"target_cpu": "<cpu_id>",
"os": "<os_type>",
"language": "<language>",
"template": "<app_template>",
"bsp": "<bsp_name>",
"bsp_lib": {
"<lib_name>": {
"version": "<lib_version>",
"config": {
"<parameter0>": "<value0>",
"<parameter1>": "<value1>"
}
}
},
"bsp_config": {
"<parameter0>": "<value0>",
"<parameter1>": "<value1>"
},
"mem_layout" : {
"heap_size": "<heap_size>",
"stack_size": "<stack_size>"
},
"build_config": {
"<config_name>": {
"assembler-flags": "<assembler-flags>",
"compiler-misc": "<compiler-misc>",
"compiler-optimization": "<compiler-optimization>",
"linker-misc": "<linker-misc>",
"linker-script": "<linker-script>",
"define-compiler-symbols": ["<symbol0>", "<symbol1>"],
"undef-compiler-symbols": ["<symbol0>", "<symbol1>"],
"include-path": ["<dir0>", "<dir1>"],
"libraries": ["<lib0>", "<lib1>"],
"library-search-path": ["<dir0>", "<dir1>"]
}
}
}
}
```
- **sources**: 源文件列表,可使用通配符。例如,`"src/*"` 会将当前工作路径下的 `src` 文件夹中的所有文件复制或链接到相应工程目录下的 `src` 文件夹中。
- **target_cpu**: 目标 CPU ID[^2];
- **os**: 操作系统类型[^1],必须与 BSP/Domain 匹配;
- **language**: 编程语言,"C" 或 "C++";
- *template*: 所使用的应用模板名称,不指定则默认为对应语言的 “Empty Application”;
- *bsp*: 应用所使用的 BSP 名称,若未指定则会自动创建名为 `<app_name>_bsp` 的 BSP/Domain.
- *bsp_lib*: 针对自动创建的 BSP/Domain 所使用库的配置,与 [bsps](#bsps) 中 `libs` 对应;
- *bsp_config*: 针对自动创建的 BSP/Domain 配置与 [bsps](#bsps) 中 `config` 对应;
- *mem_layout*: 应用内存布局,包括堆栈大小和堆大小等;
-*heap_size*: 堆大小,必须写为十六进制,例如 "0x80000";
-*stack_size*: 栈大小,必须写为十六进制,例如 "0x4000";
- *build_config*: 编译目标配置,`release` 或 `debug`;
- `assembler-flags`: 汇编器标志;
- `compiler-misc`: 其他编译器选项;
- `compiler-optimization`: 编译优化选项;
- `linker-misc`: 链接器选项;
- `linker-script`: 链接脚本路径[^3];
- `define-compiler-symbols`: 自定义的编译器宏定义符号列表;
- `undef-compiler-symbols`: 要取消定义的符号列表;
- `include-path`: 包含文件路径[^3];
- `libraries`: 需要链接的库;
- `library-search-path`: 库搜索路径[^3];
以下配置添加了一个名为 `demo_app` 的 Application 工程,该工程没有指定 BSP/Domain 但能够通过 `bsp_lib` 和 `bsp_config` 自动生成一个名为 `standalone_ps7_cortexa9_0` 的 BSP/Domain 工程。
```json
"apps": {
"demo_app": {
"sources": ["source/"],
"target_cpu": "ps7_cortexa9_0",
"os": "standalone",
"language": "C",
"bsp_lib": {
"xilffs": {
"version": "5.2",
"config": {
"use_lfn": true,
"enable_exfat": true
}
}
},
"bsp_config": {
"sleep_timer": "ps7_globaltimer_0",
"stdin": "ps7_uart_1",
"stdout": "ps7_uart_1"
},
"mem_layout" : {
"heap_size": "0x80000",
"stack_size": "0x4000"
},
"build_config": {
"debug": {
"define-compiler-symbols": ["XILINX_PLATFORM", "_DEBUG_LEVEL_=1"],
"include-path": ["source/include"],
},
"release": {
"define-compiler-symbols": ["XILINX_PLATFORM"],
"include-path": ["source/include"],
}
}
}
}
```
[^1]: 具体可配置项取决于对应 IDE 版本;
[^2]: 具体可选 CPU ID 取决于硬件型号;
[^3]: 相对对应工程的文件夹的路径;
+44
View File
@@ -0,0 +1,44 @@
@echo off
REM Check if exactly two arguments are provided and not empty
if "%~2"=="" (
echo Usage: build.bat ^<config^> ^<work_dir^>
exit /b 1
)
if not "%~3"=="" (
echo Usage: build.bat ^<config^> ^<work_dir^>
exit /b 1
)
REM Check if the config file exists
set "config=%1"
if not exist "%config%" (
echo Error: Config file "%config%" does not exist.
exit /b 1
)
REM Check if the build directory already exists
set "work_dir=%2"
if exist "%work_dir%" (
echo Error: The build folder already exists.
echo "%work_dir%" folder needs to be deleted before the project can be recreated.
exit /b 1
)
REM Create the build directory
mkdir "%work_dir%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to create the build directory: "%work_dir%".
exit /b 1
)
REM Start xsct and wait for it to finish
echo Invoking project build...
@REM cmd /c "cd /d %~dp0 && xsct util.tcl create_project \"%config%\" \"%work_dir%\" || exit /b %errorlevel%"
xsct %~dp0util.tcl create_project "%config%" "%work_dir%"
if %errorlevel% NEQ 0 (
echo Error: xsct execution failed with error code %ERRORLEVEL%.
echo Please check your configurations.
exit /b %ERRORLEVEL%
)
exit /b 0
+53
View File
@@ -0,0 +1,53 @@
@echo off
REM Check if exactly two arguments are provided and not empty
if "%~2"=="" (
echo Usage: launch.bat ^<version^> ^<work_dir^>
exit /b 1
)
if not "%~3"=="" (
echo Usage: launch.bat ^<version^> ^<work_dir^>
exit /b 1
)
REM Use regex to check if input version code is valid
set "xilinx_version=%1"
set "version_pattern=20[12][01234789][.][12]"
echo %xilinx_version% | findstr /r /c:"%version_pattern%" >nul
if %errorlevel% NEQ 0 (
echo Error: %xilinx_version% is not a valid version coede ^(e.g., 2019.1^)
exit /b 1
)
REM Check if the build directory already exists
set "work_dir=%2"
if not exist "%work_dir%" (
echo Error: no `%work_dir%' folder
echo try to create project before launching SDK
pause >nul
)
REM Convert it to a integer
for /f "tokens=1,2 delims=." %%a in ("%xilinx_version%") do (
set major=%%a
set minor=%%b
)
set /a version_number=%major%%minor%
set /a lowest_vits_version=20192
set /a new_vits_version=20232
REM Determine which tool to launch based on the Xilinx version
if %version_number% lss %lowest_vits_version% (
REM Version is less than 2019.2, use xsdk
echo Launching Xilinx SDK...
xsdk -workspace "%work_dir%"
) else if %version_number% lss %new_vits_version% (
REM Version is between 2019.2 and 2023.1, use vitis
echo Launching Xilinx Vitis...
vitis -workspace "%work_dir%"
) else (
REM Version is 2023.2 or higher, use vitis -classic
echo Launching Xilinx Vitis Classic...
vitis -classic -workspace "%work_dir%"
)
exit /b 0
+61
View File
@@ -0,0 +1,61 @@
@echo off
REM Check if exactly two arguments are provided and not empty
if "%~1"=="" (
echo Usage: setenv_xilinx.bat ^<version^>
exit /b 1
)
if not "%~2"=="" (
echo Usage: setenv_xilinx.bat ^<version^>
exit /b 1
)
REM Use regex to check if input version code is valid
set "xilinx_version=%1"
set "version_pattern=20[12][01234789][.][12]"
echo %xilinx_version% | findstr /r /c:"%version_pattern%" >nul
if %errorlevel% NEQ 0 (
echo Error: %xilinx_version% is not a valid version code ^(e.g., 2019.1^)
exit /b 1
)
REM Prompt user for Xilinx installation path, default to C:\Xilinx if not provided
set "default_path=C:\Xilinx"
set /p "xilinx_path=Enter Xilinx installation path (press Enter for default: %default_path%): "
if "%xilinx_path%"=="" (
set "xilinx_path=%default_path%"
)
REM Reset ERRORLEVEL to avoid false error codes
verify > nul
REM Convert version to integer
for /f "tokens=1,2 delims=." %%a in ("%xilinx_version%") do (
set major=%%a
set minor=%%b
)
set /a version_number=%major%%minor%
set /a lowest_vitis_version=20192
REM Determine the correct settings.bat path based on the Xilinx version and user path
if %version_number% lss %lowest_vitis_version% (
echo Setting up environment for Xilinx SDK %xilinx_version%.
set settings_bat=%xilinx_path%\SDK\%xilinx_version%\settings64.bat
) else (
echo Setting up environment for Xilinx Vitis %xilinx_version%.
set settings_bat=%xilinx_path%\Vitis\%xilinx_version%\settings64.bat
)
REM Check if the settings.bat file exists
if not exist "%settings_bat%" (
echo Error: Could not find settings file at %settings_bat%.
echo Please check your Xilinx tools installation.
exit /b 1
)
REM Call the settings.bat file to set up the environment
call "%settings_bat%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to call "%settings_bat%"
exit /b 1
)
exit /b 0
+32
View File
@@ -0,0 +1,32 @@
# Buid folder
build/
# Xilinx tools generated files
.metadata/
.settings/
.wsdata/
.Xil/
logs/
Packages/
*.log*
# System generated files
# -- macOS
.DS_Store
.AppleDouble
.LSOverride
._*
# -- Windows
Thumbs.db
ehthumbs.db
Desktop.ini
# -- Linux
*~
# IDEs and editors' files
*.idea
*.vscode
*.sublime-workspace
*.sublime-project
+69
View File
@@ -0,0 +1,69 @@
{
"project_name": "<project_name>",
"version": "<project_version>",
"hw_design": "<hw_design>",
"fsbl_patch": {
"<patch_target0>": "<patch_file0>",
"<patch_target1>": "<patch_file1>"
},
"bsps": {
"<bsp_name>": {
"os": "<os_type>",
"target_cpu": "<cpu_id>",
"lib": {
"<lib_name>": {
"version": "<lib_version>",
"config": {
"<parameter0>": "<value0>",
"<parameter1>": "<value1>"
}
}
},
"config": {
"<parameter0>": "<value0>",
"<parameter1>": "<value1>"
}
}
},
"apps": {
"<app_name>": {
"sources": ["dir0", "dir1"],
"target_cpu": "<cpu_id>",
"os": "<os_type>",
"language": "<language>",
"template": "<app_template>",
"bsp": "<bsp_name>",
"bsp_lib": {
"<lib_name>": {
"version": "<lib_version>",
"config": {
"<parameter0>": "<value0>",
"<parameter1>": "<value1>"
}
}
},
"bsp_config": {
"<parameter0>": "<value0>",
"<parameter1>": "<value1>"
},
"mem_layout" : {
"heap_size": "<heap_size>",
"stack_size": "<stack_size>"
},
"build_config": {
"<config_name>": {
"assembler-flags": "<assembler-flags>",
"compiler-misc": "<compiler-misc>",
"compiler-optimization": "<compiler-optimization>",
"linker-misc": "<linker-misc>",
"linker-script": "<linker-script>",
"define-compiler-symbols": ["<symbol0>", "<symbol1>"],
"undef-compiler-symbols": ["<symbol0>", "<symbol1>"],
"include-path": ["<dir0>", "<dir1>"],
"libraries": ["<lib0>", "<lib1>"],
"library-search-path": ["<dir0>", "<dir1>"]
}
}
}
}
}
+480
View File
@@ -0,0 +1,480 @@
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
platform generate -domains "$bsp_name"
} 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 recursively create hard links for files in a directory
proc _link_or_copy_dir {source_dir target_dir link_mode} {
# Create target directory if it doesn't exist
if {![file exists $target_dir]} {
file mkdir $target_dir
_info "Created directory: $target_dir"
}
# Process each file and subdirectory in the source directory
foreach item [glob -nocomplain -directory $source_dir *] {
set item_name [file tail $item]
set target_item [file join $target_dir $item_name]
# Remove existing file or directory
if {[file exists $target_item]} {
file delete -force $target_item
_warn "Deleted existing item: $target_item"
}
if {[file isfile $item]} {
# Handle file - create hard link or copy
if {$link_mode eq "y"} {
if {[catch {
file link -hard $target_item $item
} err]} {
error "Failed to create hard link: $err"
} else {
_info "Created hard link: $target_item -> $item"
}
} else {
file copy $item $target_item
_info "Copied file: $item to $target_item"
}
} elseif {[file isdirectory $item]} {
# Handle subdirectory recursively
_link_or_copy_dir $item $target_item $link_mode
}
}
}
# 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"
}
# Handle 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]
if {[file isfile $eval_source]} {
# For files, ensure the parent 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 file if it exists
if {[file exists $target_path]} {
file delete -force $target_path
_warn "Deleted existing file: $target_path"
}
# Handle file based on LINK_SRCS
if {$link_srcs eq "y"} {
if {[catch {
file link -hard $target_path $eval_source
} err]} {
error "Failed to create hard link: $err"
}
_info "Created hard link: $target_path -> $eval_source"
} else {
file copy $eval_source $target_path
_info "Copied file: $eval_source to $target_path"
}
} else {
# For directories, use the helper function
_link_or_copy_dir $eval_source $target_path $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 ""} {
set value_list [list $value]
eval $cmd $app_name -set $param $value_list
_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 sources [dict get $app_config sources]
set bsp_name "${app_name}_bsp"
set lang [dict get $app_config language]
if { $lang ne "C" && $lang ne "C++" } {
_error "Unsupport language" "language should be C or C++"
}
if { [dict exists $app_config template] } {
set template [dict get $app_config template]
} elseif { !$is_vitis } {
set template "Empty Application"
} elseif { $lang eq "C++" } {
set template "Empty Application (C++)"
} else {
set template "Empty Application(C)"
}
# 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]
if {![dict exists $::config bsps]} {
_error "BSP configuration missing" "The 'bsps' section is not found in the configuration."
} elseif {![dict exists [dict get $::config bsps] $bsp_name]} {
_error "BSP configuration missing" "No configuration found for BSP '$bsp_name' in the 'bsps' section."
} else {
_info "Configuring BSP '$bsp_name' for application '$app_name'."
}
} 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]]
}
_info "Creating BSP $bsp_name for Application $app_name ..."
_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 "$template"
_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 "$template"
_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 [pwd]
set config [json::json2dict $config_data]
set project_name [dict get $config project_name]
set hw_file [file normalize [file join $root [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."
+49
View File
@@ -0,0 +1,49 @@
$(call check-var,XILINX_VITIS_CLASSIC)
$(call check-var,PLATFORM_TOOLS)
$(call check-var,CONFIG_FILE)
$(call check-var,BUILD_DIR)
$(call check-var,PROJECT_LOCK)
$(call check-var,BUILD_LOCK)
$(call check-var,LINK_SRCS)
define tcl_util
xsct -nodisp $(PLATFORM_TOOLS)/util.tcl \
$(1) \
$(CONFIG_FILE) $(BUILD_DIR)
endef
PHONY += xilinx_reset xilinx_project xilinx_sdkclean xilinx_sdkbuild
xilinx_sdkopen:
@$(call log,Launching IDE...)
@if [ "$(call check_command,vitis)" = "y" ]; then \
if [ "$(XILINX_VITIS_CLASSIC)" = "y" ]; then \
vitis -classic -workspace=$(BUILD_DIR); \
else \
vitis -workspace=$(BUILD_DIR); \
fi; \
elif [ "$(call check_command,xsdk)" = "y" ]; then \
xsdk -workspace=$(BUILD_DIR); \
else \
echo "No IDE found!" && exit 1; \
fi
xilinx_sdkbuild:
@$(call log,[Build] SDK projects in $(BUILD_DIR))
$(call tcl_util, build) $(HIDE)
@echo "$(TIMESTAMP): Build lock." > $(BUILD_LOCK)
xilinx_sdkclean:
@$(call log,[Delete] SDK artefacts from $(BUILD_DIR))
$(call tcl_util, clean_project) $(HIDE)
$(PROJECT_LOCK):
@$(call log,Creating and configuring the IDE project)
@$(call cmd_mkdir,$(BUILD_DIR))
$(call tcl_util, create_project) $(HIDE)
@echo "$(TIMESTAMP): Project lock." > $@
xilinx_project: $(PROJECT_LOCK)
xilinx_reset:
$(call cmd_remove,.Xil) $(HIDE)
+34
View File
@@ -0,0 +1,34 @@
@echo off
cd /d "%~dp0"
set "platform=xilinx"
set "platform_ver=2019.1"
set "work_dir=%~dp0build"
set "config=%~dp0config.json"
set "tools_dir=%~dp0scripts\platform\%platform%"
REM Set up environment
call "%tools_dir%\setenv.bat" "%platform_ver%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to initialize environment.
pause >nul
exit /b 1
)
REM Build project
call "%tools_dir%\build.bat" "%config%" "%work_dir%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to build project.
pause >nul
exit /b 1
)
REM Launch SDK
call "%tools_dir%\launch.bat" "%platform_ver%" "%work_dir%"
if "%ERRORLEVEL%" neq "0" (
echo Error: Failed to launch SDK.
pause >nul
exit /b 1
)
exit /b 0
+6
View File
@@ -0,0 +1,6 @@
include scripts/generic_variables.mk
PLATFORM := <your_platform>
CONFIG_FILE := $(PROJECT)/config.json
include scripts/generic.mk