xmake-io / xmake

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

嵌入式项目编译时自定义Toolchain链接参数不正确 #2120

Closed fripSide closed 2 years ago

fripSide commented 2 years ago

描述问题

我想通过自定义Toolchain来把大型IoT系统的嵌入式Cmake/Keil代码项目(FreeRTOS, Zephyr, LiteOS等)转成xmake。
在这之前,我先用最简单的项目进行测试,但是链接的时候出现了问题,无法正确的传入链接参数。我使用的项目如下: https://github.com/samvrlewis/minimal-stm32/blob/master/Makefile
可以看出来只需要两条命令就能编译成功:

arm-none-eabi-gcc $(C_FLAGS) -o main.o main.c
arm-none-eabi-ld -T$(LINKER_SCRIPT) -o main.elf main.o 

因此我使用自定义的toolchian:

add_rules("mode.debug", "mode.release")

toolchain("arm-gcc")
    local tool_path = "/Applications/ARM/"
    set_kind("cross")
    set_description("Stm32 Arm Embedded Compiler")
    set_sdkdir(tool_path)
    set_toolset("cc", "arm-none-eabi-gcc")
    -- set_toolset("cxx", "arm-none-eabi-g++")
    set_toolset("ld", "arm-none-eabi-ld")

    on_check(function (toolchain)
        toolchain:add("cxflags", "-c -O0 -mcpu=cortex-m3 -mthumb -g3") 
        toolchain:add("ldflags", "-Tsrc/link.ld")
        -- toolchain:configs_save()
        return true
    end)
toolchain_end()

set_plat("cross")
set_toolchains("arm-gcc")

target("mini-stm32")
    set_kind("binary")
    add_files("src/*.c")

期待的结果

前面的gcc命令执行正常,到了link的时候就多了参数:“-Wl, -x”。希望ldflags能自己clear或者完全自己设置。

/Applications/ARM/bin/arm-none-eabi-ld -o build/cross/x86_64/release/mini-stm32 build/.objs/mini-stm32/cross/x86_64/release/src/main.c.o -Tsrc/link.ld -Wl,-x

正常编译命令:

/Applications/ARM/bin/arm-none-eabi-ld -o build/cross/x86_64/release/minimal-proj build/.objs/minimal-proj/cross/x86_64/release/src/main.c.o -Tsrc/link.ld

错误信息

$ xmake f --toolchain=arm-gcc -c -vD
checking for platform ... macosx
checking for architecture ... x86_64
configure
{
    plat = macosx
    host = macosx
    arch = x86_64
    ccache = true
    toolchain = arm-gcc
    buildir = build
    mode = release
    kind = static
    clean = true
    ndk_stdcxx = true
}

$ xmake b -vD
checking for arm-none-eabi-gcc ... /Applications/ARM/bin/arm-none-eabi-gcc
checking for the c compiler (cc) ... arm-none-eabi-gcc
checking for /Applications/ARM/bin/arm-none-eabi-gcc ... ok
checking for flags (-fPIC) ... ok
> arm-none-eabi-gcc "-fPIC"
checking for flags (-O3) ... ok
> arm-none-eabi-gcc "-O3"
checking for flags (-DNDEBUG) ... ok
> arm-none-eabi-gcc "-DNDEBUG" "-c" "-O0" "-mcpu=cortex-m3" "-mthumb" "-g3"
checking for arm-none-eabi-ld ... /Applications/ARM/bin/arm-none-eabi-ld
checking for the linker (ld) ... arm-none-eabi-ld
[ 50%]: linking.release mini-stm32
/Applications/ARM/bin/arm-none-eabi-ld -o build/cross/x86_64/release/mini-stm32 build/.objs/mini-stm32/cross/x86_64/release/src/main.c.o -Tsrc/link.ld -Wl,-x
error: @programdir/modules/private/async/runjobs.lua:232: @programdir/actions/build/kinds/binary.lua:74: @programdir/core/sandbox/modules/os.lua:264: /Applications/ARM/bin/arm-none-eabi-ld: unrecognized option '-Wl,-x'
/Applications/ARM/bin/arm-none-eabi-ld: use the --help option for usage information

stack traceback:
    [C]: in function 'error'
    [@programdir/core/base/os.lua:827]:
    [@programdir/core/sandbox/modules/os.lua:264]: in function 'runv'
    [@programdir/modules/core/tools/ld.lua:88]:
    [C]: in function 'xpcall'
    [@programdir/core/base/utils.lua:280]:
    [@programdir/actions/build/kinds/binary.lua:74]: in function 'callback'
    [@programdir/modules/core/project/depend.lua:189]: in function 'on_changed'
    [@programdir/actions/build/kinds/binary.lua:55]: in function '_do_link_target'
    [@programdir/actions/build/kinds/binary.lua:102]:
    [@programdir/actions/build/kinds/binary.lua:129]: in function '_link_target'
    [@programdir/actions/build/kinds/binary.lua:157]: in function 'jobfunc'
    [@programdir/modules/private/async/runjobs.lua:208]:
    [C]: in function 'xpcall'
    [@programdir/core/base/utils.lua:280]: in function 'trycall'
    [@programdir/core/sandbox/modules/try.lua:121]: in function 'try'
    [@programdir/modules/private/async/runjobs.lua:200]: in function 'cotask'
    [@programdir/core/base/scheduler.lua:371]:

stack traceback:
    [C]: in function 'error'
    @programdir/core/base/os.lua:827: in function 'os.raiselevel'
    (...tail calls...)
    @programdir/modules/private/async/runjobs.lua:232: in field 'catch'
    @programdir/core/sandbox/modules/try.lua:127: in global 'try'
    @programdir/modules/private/async/runjobs.lua:200: in upvalue 'cotask'
    @programdir/core/base/scheduler.lua:371: in function <@programdir/core/base/scheduler.lua:368>

很明显,是ld的时候后面多了“ -Wl,-x“ 参数,这个参数不是我自己配置的。而arm-none-eabi-ld不支持这两个参数。如果没有这两个参数就能编译成功。

相关环境

请提供编译和运行环境信息,下面是一些必须填写的基础信息,便于我们针对性排查问题:

其他信息

如果想支持嵌入式编译,可以把设置cc以及flag的命令都开放给我们就行了。下面的keil有点封装的过度了: https://github.com/xmake-io/xmake/blob/master/xmake/toolchains/armcc/xmake.lua

另外希望cross编译,自定义toolchian的时候,不要进行默认编译器check(让开发者自定义就行),例如:fPIC在arm-none-eabi-gcc 下没意义。这些check可能无法通过编译器检查。

checking for flags (-fPIC) ... ok
> arm-none-eabi-gcc "-fPIC"
checking for flags (-O3) ... ok
> arm-none-eabi-gcc "-O3"
waruqi commented 2 years ago

先确认下 dev 版本是否 ok,xmake update -s dev

fripSide commented 2 years ago

感谢回复。dev版本还是有这样问题。感觉是每种架构下的链接参数生成的时候,自动添加开始和末尾的的”-Wl“导致的。

目前用一种很不完美的办法解决了:

# 初始化项目不要用默认的 x86_64而是指定为其他架构
xmake f -p cross -a cortex-m4 --toolchain=arm-gcc -c -vD

设置cross架构为 cortex-m4,就不会自动改加载x86_64的链接参数 -Wl,-x了。cortex-m3/4最后面自动加的是 -s:

/Applications/ARM/bin/arm-none-eabi-ld -o build/cross/cortex-m4/release/mini-stm32 build/.objs/mini-stm32/cross/cortex-m4/release/src/main.c.o -Tsrc/link.ld -s

-s参数对arm-none-eabi-ld 来说没意义,但是不会报错。这样就能成功编译。

一直很想找一个这样简单快速的编译系统,命令上能和makefile一样简洁,速度上和ninja一样。后面等我有时间再写个readme到文档,说下怎么交叉编译iot项目。Keil的后面我可以帮你们重写下,之前写过简单的keil项目生产工具。

waruqi commented 2 years ago

在更新到 dev 试试

fripSide commented 2 years ago

xmake update -s dev,更新无效:仍然是xmake v2.6.3+202203021208。我试试别的安装方法。不过安装路径在哪里?我找了好久。

另外ccache有bug,连续两次编译,只要触发cccahe之后,编译参数就不对(toolchain的flags没有传递到ccahe):

xmake b -vD
checking for arm-none-eabi-gcc ... /Applications/ARM/bin/arm-none-eabi-gcc
checking for the c compiler (cc) ... arm-none-eabi-gcc
checking for the c compiler (cc) ... arm-none-eabi-gcc
checking for /Applications/ARM/bin/arm-none-eabi-gcc ... ok
checking for flags (-fPIC) ... ok
> arm-none-eabi-gcc "-fPIC"
checking for flags (-O3) ... ok
> arm-none-eabi-gcc "-O3"
checking for flags (-DNDEBUG) ... ok
> arm-none-eabi-gcc "-DNDEBUG" "-fno-common" "-ffreestanding" "-O0" "-gdwarf-2" "-g3" "-Wall" "-Werror" "-mcpu=cortex-m3" "-mthumb" "-nostartfiles"
checking for ccache ... /usr/local/bin/ccache
[ 20%]: ccache compiling.release src/main.c
/usr/local/bin/ccache /Applications/ARM/bin/arm-none-eabi-gcc -c -fno-common -ffreestanding -O0 -gdwarf-2 -g3 -Wall -Werror -mcpu=cortex-m3 -mthumb -nostartfiles -fvisibility=hidden -O3 -DNDEBUG -o build/.objs/minimal-proj/cross/cortex-m4/release/src/main.c.o src/main.c
[ 20%]: ccache compiling.release src/startup.c
/usr/local/bin/ccache /Applications/ARM/bin/arm-none-eabi-gcc -c -fno-common -ffreestanding -O0 -gdwarf-2 -g3 -Wall -Werror -mcpu=cortex-m3 -mthumb -nostartfiles -fvisibility=hidden -O3 -DNDEBUG -o build/.objs/minimal-proj/cross/cortex-m4/release/src/startup.c.o src/startup.c
checking for flags (-MMD -MF) ... ok
> arm-none-eabi-gcc "-MMD" "-MF" "/dev/null" "-fno-common" "-ffreestanding" "-O0" "-gdwarf-2" "-g3" "-Wall" "-Werror" "-mcpu=cortex-m3" "-mthumb" "-nostartfiles"
checking for flags (-fdiagnostics-color=always) ... ok
> arm-none-eabi-gcc "-fdiagnostics-color=always" "-fno-common" "-ffreestanding" "-O0" "-gdwarf-2" "-g3" "-Wall" "-Werror" "-mcpu=cortex-m3" "-mthumb" "-nostartfiles"
checking for arm-none-eabi-ld ... /Applications/ARM/bin/arm-none-eabi-ld
checking for the linker (ld) ... arm-none-eabi-ld
[ 60%]: linking.release minimal-proj
/Applications/ARM/bin/arm-none-eabi-ld -o build/cross/cortex-m4/release/minimal-proj build/.objs/minimal-proj/cross/cortex-m4/release/src/main.c.o build/.objs/minimal-proj/cross/cortex-m4/release/src/startup.c.o -s -Tsrc/main.ld
[100%]: build ok!

$ xmake b -vD
checking for flags (-DNDEBUG) ... ok
> arm-none-eabi-gcc "-DNDEBUG"
[ 20%]: ccache compiling.release src/main.c
/usr/local/bin/ccache /Applications/ARM/bin/arm-none-eabi-gcc -c -fvisibility=hidden -O3 -DNDEBUG -o build/.objs/minimal-proj/cross/cortex-m4/release/src/main.c.o src/main.c
[ 20%]: ccache compiling.release src/startup.c
/usr/local/bin/ccache /Applications/ARM/bin/arm-none-eabi-gcc -c -fvisibility=hidden -O3 -DNDEBUG -o build/.objs/minimal-proj/cross/cortex-m4/release/src/startup.c.o src/startup.c
checking for flags (-MMD -MF) ... ok
> arm-none-eabi-gcc "-MMD" "-MF" "/dev/null"
checking for flags (-fdiagnostics-color=always) ... ok
> arm-none-eabi-gcc "-fdiagnostics-color=always"
[ 60%]: linking.release minimal-proj
/Applications/ARM/bin/arm-none-eabi-ld -o build/cross/cortex-m4/release/minimal-proj build/.objs/minimal-proj/cross/cortex-m4/release/src/main.c.o build/.objs/minimal-proj/cross/cortex-m4/release/src/startup.c.o -s -Tsrc/main.ld
error: @programdir/modules/private/async/runjobs.lua:232: @programdir/actions/build/kinds/binary.lua:74: @programdir/core/sandbox/modules/os.lua:249: /Applications/ARM/bin/arm-none-eabi-ld: build/.objs/minimal-proj/cross/cortex-m4/release/src/startup.c.o: in function `reset_handler':
startup.c:(.text+0x174): undefined reference to `memcpy'
/Applications/ARM/bin/arm-none-eabi-ld: startup.c:(.text+0x19c): undefined reference to `memset'

stack traceback:
    [C]: in function 'error'
    [@programdir/core/base/os.lua:849]:
    [@programdir/core/sandbox/modules/os.lua:249]: in function 'runv'
    [@programdir/modules/core/tools/ld.lua:81]:
    [C]: in function 'xpcall'
    [@programdir/core/base/utils.lua:280]:
    [@programdir/actions/build/kinds/binary.lua:74]: in function 'callback'
    [@programdir/modules/core/project/depend.lua:189]: in function 'on_changed'
    [@programdir/actions/build/kinds/binary.lua:55]: in function '_do_link_target'
    [@programdir/actions/build/kinds/binary.lua:102]:
    [@programdir/actions/build/kinds/binary.lua:129]: in function '_link_target'
    [@programdir/actions/build/kinds/binary.lua:157]: in function 'jobfunc'
    [@programdir/modules/private/async/runjobs.lua:208]:
    [C]: in function 'xpcall'
    [@programdir/core/base/utils.lua:280]: in function 'trycall'
    [@programdir/core/sandbox/modules/try.lua:121]: in function 'try'
    [@programdir/modules/private/async/runjobs.lua:200]: in function 'cotask'
    [@programdir/core/base/scheduler.lua:371]:

stack traceback:
    [C]: in function 'error'
    @programdir/core/base/os.lua:849: in function 'os.raiselevel'
    (...tail calls...)
    @programdir/modules/private/async/runjobs.lua:232: in field 'catch'
    @programdir/core/sandbox/modules/try.lua:127: in global 'try'
    @programdir/modules/private/async/runjobs.lua:200: in upvalue 'cotask'
    @programdir/core/base/scheduler.lua:371: in function <@programdir/core/base/scheduler.lua:368>

正确参数

/usr/local/bin/ccache /Applications/ARM/bin/arm-none-eabi-gcc -c -fno-common -ffreestanding -O0 -gdwarf-2 -g3 -Wall -Werror -mcpu=cortex-m3 -mthumb -nostartfiles -fvisibility=hidden -O3 -DNDEBUG -o build/.objs/minimal-proj/cross/cortex-m4/release/src/startup.c.o src/startup.c

错误参数:

 ccache compiling.release src/startup.c
/usr/local/bin/ccache /Applications/ARM/bin/arm-none-eabi-gcc -c -fvisibility=hidden -O3 -DNDEBUG -o build/.objs/minimal-proj/cross/cortex-m4/release/src/startup.c.o src/startup.c

解决方法

不要在toolchian添加任何编译参数,直接在target哪里添加,这样就不会触发不正确的ccache:

target("minimal-proj")
    set_kind("binary")
    add_files("src/*.c")
    add_cxflags("-fno-common", "-ffreestanding", "-O0", "-gdwarf-2", 
    "-g3", "-Wall", "-Werror", 
    "-mcpu=cortex-m3", "-mthumb", "-nostartfiles")
    add_ldflags("-Tsrc/main.ld", {force=true})
fripSide commented 2 years ago

另外,cross= cortex-m4,下toolchain的ldflags添加无效,需要去下面src哪里添加:

toolchain("arm-gcc")
    local tool_path = "/Applications/ARM/"
    set_kind("cross")
    set_description("Stm32 Arm Embedded Compiler")
    set_sdkdir(tool_path)
    set_toolset("cc", "arm-none-eabi-gcc")
    -- set_toolset("cxx", "arm-none-eabi-g++")
    set_toolset("ld", "arm-none-eabi-ld")

    on_check(function (toolchain)
        toolchain:add("cxflags", "-fno-common", "-ffreestanding", "-O0", "-gdwarf-2", 
        "-g3", "-Wall", "-Werror", 
        "-mcpu=cortex-m3", "-mthumb", "-nostartfiles") 
        toolchain:add("ldflags", "-Tsrc/main.ld", {force=true})
        toolchain:configs_save()
        return true
    end)
toolchain_end()

set_toolchains("arm-gcc")

target("minimal-proj")
    set_kind("binary")
    add_files("src/*.c")
    add_ldflags("-Tsrc/main.ld", {force=true})

这个是不起作用的:
toolchain:add("ldflags", "-Tsrc/main.ld", {force=true})

需要在下面单独添加:
add_ldflags("-Tsrc/main.ld", {force=true})

只要把flags这一块,不添加任何默认操作,取toolchain和target的并集:脚本flags = toolchain(flag) U target(flag)。并且提供API reset flags,让在target中能够clear所有的flags,应该就能满足几乎所有的需求。我就能去编译大型RTOS。

waruqi commented 2 years ago

xmake update -s dev,更新无效:仍然是xmake v2.6.3+202203021208。我试试别的安装方法。不过安装路径在哪里?我找了好久。

-s 仅更新脚本,core 版本不会变。先确认是否生效,不行,就再贴 -vD 的完整输出和错误。

其他问题,单开 issues,不要混着问

fripSide commented 2 years ago

使用 xmake update dev, 更新到dev版本:
xmake v2.6.3+dev.bcf29f1

:beers: 新版本没问题,不会再自动增加链接(-Wl, -x)参数(但还是有-s)。另外: toolchain:add("ldflags") 和toolchain:add("cxflags")不生效是我配置写错了,写到on_check里面了,应该放到on_load里面。这是能正确运行的xmake脚本:

add_rules("mode.debug", "mode.release")
set_plat("cross")

toolchain("arm-gcc")
    local tool_path = "/Applications/ARM/"
    set_kind("cross")
    set_description("Stm32 Arm Embedded Compiler")
    set_sdkdir(tool_path)
    set_toolset("cc", "arm-none-eabi-gcc")
    -- set_toolset("cxx", "arm-none-eabi-g++")
    set_toolset("ld", "arm-none-eabi-ld")

    on_load(function (toolchain)
        toolchain:add("cxflags", "-fno-common", "-ffreestanding", "-O0", "-gdwarf-2", 
        "-g3", "-Wall", "-Werror", 
        "-mcpu=cortex-m3", "-mthumb", "-nostartfiles") 
        toolchain:add("ldflags", "-Tsrc/main.ld", {force=true})
    end)
toolchain_end()

set_toolchains("arm-gcc")

target("minimal-proj")
    set_kind("binary")
    add_files("src/*.c")

    after_build(function (target)
        print("after_build")
    local out = target:targetfile() or ""
        local bin_out = " build/minimal-proj.bin"
        print(string.format("%s => %s", out, bin_out))
        os.exec("arm-none-eabi-objcopy -Obinary "..out.." "..bin_out)
        os.exec("qemu-system-arm -M stm32-p103 -nographic -kernel"..bin_out)
    end)

build项目:

xmake f --toolchain=arm-gcc -c
xmake b -vD

@waruqi 非常感谢你的帮助,这个issue可以关闭了。后面我试试用这个工具完全代替Cmake。