CMake:使用自定义链接器

wlsrxk51  于 2023-03-30  发布在  其他
关注(0)|答案(9)|浏览(374)

我想用CMake设置一个自定义工具链。我已经设置了编译器,但我不知道如何设置链接器。报告此错误是因为CMake尝试使用编译器链接:

The C compiler "xgcc.exe" is not able to compile a simple test program.

这里有一个我的工具链文件的片段

# specify the cross compiler
INCLUDE(CMakeForceCompiler)
SET(CMAKE_C_COMPILER   xgcc.exe)
SET(CMAKE_CXX_COMPILER xgcc.exe)
#CMAKE_FORCE_C_COMPILER(xgcc.exe GNU)
#CMAKE_FORCE_CXX_COMPILER(xgcc.exe GNU)

我已经尝试强制编译器,但链接器的问题不会得到解决。

wwwo4jvm

wwwo4jvm1#

link命令行在Modules/CMake{C,CXX,Fortran}Information.cmake中设置,默认使用 compiler,而不是CMAKE_LINKER(参见源代码)。这可以通过替换构建link命令行的规则来更改,该规则存在于变量CMAKE_CXX_LINK_EXECUTABLE(和朋友)中。注意,该变量不指示指向链接器可执行文件的路径;它说如何链接可执行文件!
一种方法是设置该规则以使用链接器,例如

cmake -DCMAKE_LINKER=/path/to/linker -DCMAKE_CXX_LINK_EXECUTABLE="<CMAKE_LINKER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>"

参见this post from CMake mailing listthis one--这也是一个自然的地方,可以在另一个连接器前添加一个连接器修饰符。

pgvzfuti

pgvzfuti2#

正如Mabraham指出的,CMake调用编译器来做链接。所以,* 到目前为止***最简单的解决方案是LET IT,并在调用时告诉 * 编译器 * 运行不同的链接器。
正如在this other answer中所指出的-但现在它甚至是gcc --help=common中的文档选项-就像下面一样简单:

cmake -DCMAKE_CXX_FLAGS="-fuse-ld=lld"

g++clang++将在每次调用时传递-fuse-ld=lld 1标志,当它们进行任何链接时,它们将使用指定的命令而不是内置的默认命令。
(BTW,该选项被解析为(-f)(use-ld)(=)(lld),没有到gcc的“fuse”选项。)

注意事项

1.当使用Clang时,lld可以替换为您想要使用的任何其他链接器命令,如ld.exeld.goldmingw32/bin/ld.exe等。
GCC没有那么灵活,它的-fuse-ld只接受有限的一组可能的参数。(它们在gcc --help=common输出中列出,从GCC 12.2.1开始,列表是:bfdgoldlldmold。)它将调用在PATH上找到的第一个匹配的ld.*foo*可执行文件。(感谢bviktor指出GCC在选择替代链接器方面的限制。)

vuv7lop3

vuv7lop33#

CMake只给你直接控制每种语言的编译器。要调用链接器,它需要经过配置的编译器。这意味着在CMake中没有通用的方法来设置链接器,你必须配置你的编译器来使用你想要的链接器。
这些标志需要在CMake的编译器检测例程运行之前设置,因为它会尝试编译一个测试二进制文件。最好的方法是创建一个toolchain file。在工具链文件中设置这些标志的最佳方法如下:

# e.g. to use lld with Clang
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld")

这三个变量分别控制可执行程序、可加载模块和共享库的链接器标志(默认)集。这里不需要处理CMAKE_STATIC_LINKER_FLAGS_INIT(对于静态库),因为调用的是 archiver,而不是链接器。
然后,您可以在 * 第一次 * 运行CMake时通过在命令行设置-DCMAKE_TOOLCHAIN_FILE=/path/to/toolchain.cmake来设置工具链文件。从CMake 3.21开始,您将能够传递--toolchain /path/to/toolchain.cmake(这是完全等效的,但输入较少)。

xn1cxnb4

xn1cxnb44#

我成功地做了

add_link_options("-fuse-ld=lld")

这是前面答案的一个变体,不同之处在于我用来设置标志的CMake命令。
将其添加到CMAKE_CXX_FLAGS的缺点是,还必须添加-Wno-unused-command-line-argument,因为标志也会添加到编译命令中,而不仅仅是链接命令。
CMAKE_SHARED_LINKER_FLAGS的缺点是你必须多次添加它,到_SHARED__EXE_,也许我忘了什么。

hgtggwj0

hgtggwj05#

在CMakeCache.txt中或在高级选项下的ccmake .之后设置变量${CMAKE_LINKER}。

ujv3wf0j

ujv3wf0j6#

我必须使用CMAKE_CXX_LINK_EXECUTABLE,CMAKE_C_LINK_EXECUTABLE变量:

SET(CMAKE_C_LINK_EXECUTABLE "c:\\MoSync\\bin\\pipe-tool.exe")
cqoc49vn

cqoc49vn7#

下面是一个CMake函数,它根据一些预定义的任意规则(Clang -〉lld-version或lld,GCC -〉gold)设置链接器。
重要部件:
1.搜索与Clang编译器版本匹配的lld-version(如果使用Clang 13.x.x,则为lld-13),如果未找到,福尔斯到lld

add_link_options("-fuse-ld=lld-${CLANG_VERSION_MAJOR}")

1.当链接器设置为gold时,使用所有系统线程:

add_link_options("-fuse-ld=gold;LINKER:--threads,--thread-count=${HOST_PROC_COUNT}")

由于注解、日志和自定义逻辑,该示例有点太长,但它是自包含的,对于初学者来说可能是有用的起点。

function(select_best_linker) #lld for Clang and GNU gold for GCC
    if (UNIX AND NOT APPLE)
        include(ProcessorCount)
        ProcessorCount(HOST_PROC_COUNT)

        if(${CMAKE_CXX_COMPILER_ID} MATCHES Clang)

            # By default LLD uses all system threads.
            # This could be tweaked for versions 11+ (--threads=1), but cannot be disabled for older versions
            # add_link_options("-fuse-ld=lld-${CLANG_VERSION_MAJOR};LINKER:--threads=${HOST_PROC_COUNT}") #LLD>=11
            # add_link_options("-fuse-ld=lld;LINKER:--threads")#LLD <= 10 this is the default state

            string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION})
            list(GET VERSION_LIST 0 CLANG_VERSION_MAJOR) #extract major compiler version

            find_program(LLD_PROGRAM_MATCH_VER lld-${CLANG_VERSION_MAJOR}) #search for lld-13 when clang 13.x.x is used
            find_program(LLD_PROGRAM lld) #else find default lld

            if (LLD_PROGRAM_MATCH_VER) #lld matching compiler version
                message(STATUS "Set linker to LLD (multi-threaded): ${LLD_PROGRAM_MATCH_VER}")
                add_link_options("-fuse-ld=lld-${CLANG_VERSION_MAJOR}")
            elseif(LLD_PROGRAM) #default lld
                message(STATUS "Set linker to LLD (multi-threaded): ${LLD_PROGRAM}")
                add_link_options("-fuse-ld=lld")
            endif(LLD_PROGRAM_MATCH_VER)

        elseif(${CMAKE_CXX_COMPILER_ID} MATCHES GNU)

            find_program(GNU_GOLD_PROGRAM gold)
            if (GNU_GOLD_PROGRAM)
                message(STATUS "Set linker to GNU gold: ${GNU_GOLD_PROGRAM}, using threads: ${HOST_PROC_COUNT}")
                add_link_options("-fuse-ld=gold;LINKER:--threads,--thread-count=${HOST_PROC_COUNT}")
            endif(GNU_GOLD_PROGRAM)

        endif(${CMAKE_CXX_COMPILER_ID} MATCHES Clang)
    endif(UNIX AND NOT APPLE)
endfunction(select_best_linker)

测试日期:

  • Ubuntu 20.04
  • 计算机制造3.16.3
  • 通用条款9.4.0
  • 铿锵-12
  • 铿锵-13
  • GNU gold(GNU Binutils 2.37)1.16
  • LLD 10.0.0(与GNU链接器兼容)
  • Ubuntu LLD 13.0.1(与GNU链接器兼容)
j13ufse2

j13ufse28#

为了完整起见,另一个完全证明的选项是通过运行以下命令将/usr/bin/ld链接到ld.gold
sudo ln -sf /usr/bin/x86_64-linux-gnu-ld.gold /usr/bin/ld
如建议here

gblwokeq

gblwokeq9#

还有另一种方法,gcc有一个“-fuse-ld”选项,你可以在CMakeLists.txt中设置LINKER_FLAGS如下:

set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld")

则应调用定制指定的链接器。

相关问题