xmake-io / xmake

🔥 A cross-platform build utility based on Lua
https://xmake.io
Apache License 2.0
10.03k stars 783 forks source link

源码包引入在特定平台交叉编译环境下的复用问题 #2887

Closed wpchom closed 2 years ago

wpchom commented 2 years ago

你在什么场景下需要该功能?

在通用平台(如Windows/Linux,x86/arm)下,xmake的包管理还是很舒服的;在非通用平台(cortex-m)下,需要源码引入差异化构建就有点别扭。

一个真实项目情况:

Project(A/B)
├── src
│   └── main.c
├── conf
│   └── stm32f4xx_hal_conf.h    # package("stm32cube_f4")需要的配置文件,每个项目都不一样
└── xmake.lua           # 两个项目都add_requires("stm32cube_f4", {configs = {halconf = path.join(os.projectdir(), "conf")}})

参考xrepo/cross/下的一些package写法,项目相关的package文件如下:

option("lldrv") set_showmenu(true) set_default(false) option_end()

add_requires("cmsis") target("stm32f4xx_hal_driver") set_kind("$(kind)")

-- cmsis
add_packages("cmsis")

-- device
add_files("Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c")
add_includedirs("Drivers/CMSIS/Device/ST/STM32F4xx/Include", {public = true})

-- conf file
add_options("halconf")
add_includedirs(get_config("halconf"), {public = true})

-- driver
add_includedirs("Drivers/STM32F4xx_HAL_Driver/Inc", {public = true})
add_files("Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal*.c|*template.c")
add_options("lldrv")
if get_config("lldrv") then
    add_files("Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll*.c|*template.c")
end

target_end()

target("stm32cube_f4") set_kind("phony")

add_deps("stm32f4xx_hal_driver")

target_end()


- package/c/cmsis/xmake.lua

package("cmsis") set_description("CMSIS Version 5")

add_urls("https://github.com/ARM-software/CMSIS_5.git")
add_versions("5.9.0", "2b7495b8535bdcb306dac29b9ded4cfb679d7e5c")

add_configs("installdir")
add_configs("features", {default = {}})

on_load(function(package)
    if package:config("installdir") then
        package:set("installdir", path.join(package:config("installdir"), ".pkgs", package:name()))
    end

    -- rebuild when configs changed.
    os.rmdir(package:installdir())
end)

on_install(function(package)
    local srcpath = path.relative(".", package:installdir())
    package:add("includedirs", path.join(srcpath, "CMSIS", "Core", "Include"))
    if table.contains(package:config("features"), "rtos") then
        package:add("includedirs", path.join(srcpath, "CMSIS", "RTOS2", "Include"))
    end

end)

package_end()



### 描述可能的解决方案

难处:
- ```package("stm32cube_f4")```默认下载package:cachedir()在~/.xmake/cache下,默认安装package:installdir()在~/.xmake/package下,```import("package/tools/xmake.lua").install(package, configs)```在package:cachedir()下执行xmake,生成后的产物(.a/.h)会被copy到package:installdir()下的lib/include;但是对于实际项目里projA/projB共同依赖package("stm32cube_f4"),但其**配置文件(stm32f4xx_hal_conf.h)不同,生成的.a不能混用,尽管plat/arch都相同**。

- 为了分离不同项目生成的.a,将```add_requireconfs("*", {external = false, configs = {installdir = path.join(os.projectdir(), "build")}})```将installdir调整至各自projX的build目录下,同时buildir也调整至package:installdir()中;因为引入给package的**配置文件(stm32f4xx_hal_conf.h)、芯片宏定义**与proj强相关,将所有编译的中间产物(.o/.d)和最终产物(.a)都放在projX/build下相对合理。

- 按上面这个做法似乎不太符合xmake的设计理念,```add_requires("stm32cube_f4", {configs ={...}})```中的configs发生改变时,如果installdir内的.a存在,不会发生重编译,所以在package:on_load()阶段都加了一行```os.rmdir(package:installdir())```;而且package:cachedir()的路径与年月相关,导致跨月份之后package会重新下载,有点浪费空间。

- 也考虑过在package:on_install()阶段将package:cachedir()里所有内容mv到package:installdir()中,但后续```import("package/tools/xmake.lua").install(package, configs)```的编译就无法执行了,所以做了上述的动作,希望有更好的方法。

疑问:
- 是否有理想情况:源码包引入(无侵入修改),单次下载,多项目(传递配置)复用,在执行构建的项目的buildir下构建生成,include到源码路径,link到buildir下的.a?

- 因为package希望限制侵入式修改,也减少headerfiles的复制,```package:add("includedirs", "...")```时能直接include在源码路径,但这类接口好像没法识别绝对路径,都会用相对路径来引入?

- 对于headeronly的package("cmsis"),没有port/xmake.lua,被package("stm32cube_f4")依赖(能正常include到cmsis),但主project仅add_requires("stm32cube_f4")的话,无法include到依赖("stm32cube_f4")的依赖("cmsis"),```package:add("includedirs", ...)```的选项好像是没法继承依赖?

### 描述你认为的候选方案

_No response_

### 其他信息

----
PS:xmake的上手真的很简单,比起gn+ninja,都还要上个python脚本才能比得到xmake一个 >_>;
waruqi commented 2 years ago
    -- 取cachedir与installdir的相对路径,即下载的源码位置
   local srcpath = path.relative(".", package:installdir())
   -- 不做cachedir到installdir的copy,添加原始include路径
   package:add("includedirs", path.join(srcpath, "Drivers", "CMSIS", "Device", "ST", "STM32F4xx", "Include"))
   package:add("includedirs", path.join(srcpath, "Drivers", "STM32F4xx_HAL_Driver", "Inc"))

cachedir 是会被清的,直接指向过去,有可能过段时间 你就编译链接不过了。。

package("stm32cube_f4")默认下载package:cachedir()在~/.xmake/cache下,默认安装package:installdir()在~/.xmake/package下,import("package/tools/xmake.lua").install(package, configs)在package:cachedir()下执行xmake,生成后的产物(.a/.h)会被copy到package:installdir()下的lib/include;但是对于实际项目里projA/projB共同依赖package("stm32cube_f4"),但其配置文件(stm32f4xx_hal_conf.h)不同,生成的.a不能混用,尽管plat/arch都相同。

不过的 configs ,会生成不同的 buildhash 子目录,互不冲突,是可以共用的。。

需要生成不同的 stm32f4xx_hal_conf.h,那就加个 config 一一对应不同的配置项。。

参考相同包的,不同子配置共用,有demo

https://github.com/xmake-io/xmake/blob/b9225ffbb78ca4f4fa51d39524857b8f380be738/tests/projects/package/multiconfig/xmake.lua#L3-L4

通过 ~xxx 标识为不同包副本,用 alias 引用

为了分离不同项目生成的.a,将add_requireconfs("*", {external = false, configs = {installdir = path.join(os.projectdir(), "build")}})将installdir调整至各自projX的build目录下,同时buildir也调整至package:installdir()中;因为引入给package的配置文件(stm32f4xx_hal_conf.h)、芯片宏定义与proj强相关,将所有编译的中间产物(.o/.d)和最终产物(.a)都放在projX/build下相对合理。

尽量不要乱搞,按 xmake 规范走。

按上面这个做法似乎不太符合xmake的设计理念,add_requires("stm32cube_f4", {configs ={...}})中的configs发生改变时,如果installdir内的.a存在,不会发生重编译

~label

是否有理想情况:源码包引入(无侵入修改),单次下载,多项目(传递配置)复用,在执行构建的项目的buildir下构建生成,include到源码路径,link到buildir下的.a?

没必要这么搞,原本就是用 cachedir 保证源码单次下载,多次编译安装不同 configs 集成

因为package希望限制侵入式修改,也减少headerfiles的复制,package:add("includedirs", "...")时能直接include在源码路径,但这类接口好像没法识别绝对路径,都会用相对路径来引入?

只需要配置相对路径,每个 package installdir 就是一个相对独立沙盒环境,不要指向到其他地方,否则容易出问题

对于headeronly的package("cmsis"),没有port/xmake.lua,被package("stm32cube_f4")依赖(能正常include到cmsis),但主project仅add_requires("stm32cube_f4")的话,无法include到依赖("stm32cube_f4")的依赖("cmsis"),package:add("includedirs", ...)的选项好像是没法继承依赖?

可以继承,我这 ok