CMake:如何打破PRE_LINK无限循环?

时间:2017-04-26 19:48:51

标签: loops cmake dependencies prelink

我尝试使用内部版本号自动标记我的应用程序登录行。这个应用程序是一个没有图形UI的普通香草C;它适用于命令行,因此它是一个简单的"之一。

登录ID位于"模板"由CMake使用configure_file()命令自定义的源文件。最近,我想在这个登录ID中包含一个内部版本号。因此,无法再在CMake时间静态地完成自定义,但每次调用make都会被调用。

为实现这一目标,CMake有两种可能性:

  1. add_custom_target(),但即使源树中没有其他任何更改也不会反映树的状态,它也会被触发;
  2. add_custom_command(),只有在需要再次链接应用程序(目标)时才能触发。
  3. 我选择了第二种解决方案并没有成功。

    以下是 CMakeLists.txt 的摘录,登录ID位于文件 ErrAux.c (PROJECT_SOURCE_DIR中的模板,在PROJECT_BINARY_DIR中配置):

    add_executable(anathem ... ${PROJECT_BINARY_DIR}/ErrAux.c ...)
    
    add_custom_command(TARGET anathem PRE_LINK
        COMMAND "${CMAKE_COMMAND}"  "-DVERS=${PROJECT_VERSION}"
                                    "-DSRC=${PROJECT_SOURCE_DIR}"
                                    "-DDST=${PROJECT_BINARY_DIR}"
                                    -P "${CMAKE_HOME_DIRECTORY}/BuildNumber.cmake"
        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
        COMMENT "Numbering build"
        VERBATIM
    )
    

    这将在链接步骤之前启动脚本 BuildNumber.cmake 。它计算下一个内部版本号,并使用configure_file()自定义 ErrAux.c

    它工作正常,除了......

    它发生在 make 序列的后期,而对 ErrAux.c 的更新却没有引起注意。可执行文件中的登录ID包含先前的内部版本号。

    下次运行 make 时, make 会注意到生成的 ErrAux.c 比其对象模块更年轻并导致它再次被编译,这反过来导致一个触发内部版本号更新的链接。即使没有其他文件发生更改也无法解决此循环,也会发生这种情况。这在编译日志中清楚地显示:

    Scanning dependencies of target anathem
    [ 13%] Building C object AnaThem/CMakeFiles/anathem.dir/ErrAux.c.o
    [ 14%] Linking C executable anathem
    Numbering build
    3.0.0-45
    [ 36%] Built target anathem
    

    关键似乎是add_custom_command(TARGET ...)无法指定add_custom_command(OUTPUT ...)之类的输出文件。但后一种形式无法在PRE_LINK模式下触发。

    作为一种解决方法,我强制编译为"刷新"对象模块:

    add_custom_command(TARGET anathem PRE_LINK
        COMMAND "${CMAKE_COMMAND}"  "-DVERS=${PROJECT_VERSION}"
                                    "-DSRC=${PROJECT_SOURCE_DIR}"
                                    "-DDST=${PROJECT_BINARY_DIR}"
                                    -P "${CMAKE_HOME_DIRECTORY}/BuildNumber.cmake"
        COMMAND echo "Numbering"
        COMMAND echo "${CMAKE_C_COMPILER}" "\$(C_DEFINES)" "\$(C_INCLUDES)" "\$(C_FLAGS)" -c "${PROJECT_BINARY_DIR}/ErrAux.c"
        COMMAND "${CMAKE_C_COMPILER}" "\$(C_DEFINES)" "\$(C_INCLUDES)" "\$(C_FLAGS)" -c "${PROJECT_BINARY_DIR}/ErrAux.c"
        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
        COMMENT "Numbering build"
        VERBATIM
    )
    

    登录ID自定义后强制显式编译。它模仿了各种 Makefile 中的内容,而且我对生产不安全。这是 CMake make 的作弊技巧。

    更新:需要选项-c推迟链接步骤,直到最终的应用程序li​​niking过程。

    此添加会在链接中造成破坏,如日志所示,您可以在其中看到双重编译(标准 make 一个和add_custom_command()一个):

    Scanning dependencies of target anathem
    [ 13%] Building C object AnaThem/CMakeFiles/anathem.dir/ErrAux.c.o
    [ 14%] Linking C executable anathem
    Numbering build
    3.0.0-47
    Numbering
    /usr/bin/cc -DANA_DEBUG=1 -I/home/prog/projects/AnaLLysis/build/AnaThem -I/home/prog/projects/AnaLLysis/AnaThem -g /home/prog/projects/AnaLLysis/build/AnaThem/ErrAux.c
    /usr/lib/gcc/x86_64-redhat-linux/6.3.1/../../../../lib64/crt1.o: In function `_start':
    (.text+0x20): undefined reference to `main'
    collect2: error: ld returned 1 exit status
    AnaThem/CMakeFiles/anathem.dir/build.make:798: recipe for target 'AnaThem/anathem' failed
    make[2]: *** [AnaThem/anathem] Error 1
    
    <德尔> 如果我强制完全重新编译,为了确保编译所有源代码,包括* main.c *,我在`main`上得到相同的错误。 唯一合乎逻辑的解释是我的手动C调用是错误的,并以某种方式破坏重要信息。我用* readelf *检查了`main`仍然在* main.c.o *的符号表中,并且它仍然被链接步骤(来自file * link.txt *)考虑在内。

    更新:即使链接正确,我仍然会遇到无限循环综合症。生成的应用程序的登录ID仍然落后于实际的构建计数器。

    有人能给我一个正确方向的线索吗?

    仅供参考我是CMake的新手,所以我可能做错了。不要批评我的错误。

1 个答案:

答案 0 :(得分:0)

解决方案的关键是将生成的模块放在 make 期望找到它的位置。 CMake 以非平凡的方式组织构建树。

我在add_custom_command()中添加的编辑中的缺点是相信默认情况下二进制文件将存储在&#34;通常&#34; CMake 位置。由于我手动伪造我的编译器命令,情况并非如此。

我在源目录中找到了该模块,这是WORKING_DIRECTORY选项的结果,名称为 ErrAux.o ,而不是 ErrAux.co

为了获得正确的行为,我强制输出位置:

-o "${PROJECT_BINARY_DIR}/CMakeFiles/anathem.dir/ErrAux.c.o"

现在,当我再次运行 make 时,没有任何反应,因为没有任何改变。

附带问题

要使解决方案可移植(如果需要), CMakeFiles anathem.dir 目录是否有CMake变量?或者在后一种情况下,对于当前目标为&#34; anathem&#34;作为add_custom_command()中的目标名称?