繁体   English   中英

add_custom_command未生成目标

[英]add_custom_command is not generating a target

也许这是不可能的,并且我误读了cmake 3.2文档 ,但我虽然创建了一个自定义命令,但会在Makefile中创建一个自定义的“目标”,以便我可以通过调用输出文件的名称来构建目标。 CMake文档说:

用makefile术语,它以以下形式创建一个新目标:

  OUTPUT: MAIN_DEPENDENCY DEPENDS COMMAND 

所以我想我可以再运行make OUTPUT 也许文档使CMake目标与Makefile目标混淆了?

例如,

 add_custom_command(OUTPUT foo_out
    COMMAND post_process foo_in > foo_out
    DEPENDS foo_in
 )

我想要做

 make foo_out

它将成为foo_out 但是,如果我这样做,我得到

make: **** No rule to make target `foo_out`. Stop.

并且可以肯定的是,在cmake二进制输出目录中的任何文件中的任何地方都不存在单词“ foo_out”。 如果我改成这个

add_custom_target(bar DEPENDS foo_out)
add_custom_command(OUTPUT foo_out COMMAND post_process foo_in > foo_out)

那我就可以

make bar

我可以做

make foo_in

但我还是做不到

make foo_out

make bar的问题在于它不直观,因为实际文件输出是foo_out而不是bar

我该怎么做呢?

就我而言,我需要对标准可执行目标执行一个特殊的处理步骤,该步骤将可选资源插入到ELF文件中。 我希望能够将两个可执行文件都作为Makefile目标,因此我可以构建裸露的ELF可执行文件以及资源注入的ELF可执行文件。

如果我正在编写自定义的Makefile,这很简单!

foo_in: foo.c
    $(CC) $< -o $@

foo_out: foo_in
    post_process $< > $@   

我可以做make foo_inmake foo_out

add_custom_command 不会创建一个新的目标。 您必须通过add_executableadd_libraryadd_custom_target显式定义目标,以使其可见。

如果您必须为部署进行修复,则可以

1.使用install命令(在CMakeLists.txt中的某个位置),如下所示:

install(SCRIPT <dir>/post_install.cmake)

将仅当您运行make install时执行的命令存储在单独的.cmake文件中。 或者,如果安装目标已经预留给其他用途,或者您正在执行更复杂的操作:

2.手动定义部署目标。 一旦了解了这一点,就可以创建一个自定义的生成后命令,该命令仅在您在部署目标上显式运行make时才执行。 这使您可以通过单独的目标执行命令。

在您的CMakeLists.txt中,它可能类似于:

cmake_minimum_required(VERSION 3.0)

add_executable("App" <sources>)

# option 1: do deployment stuff only when installing
install(SCRIPT <dir>/post_install.cmake)

# option 2: define a deploy target and add post-build commands
add_custom_target("deploy")
add_custom_command(TARGET "deploy" POST_BUILD <some command>)

两种方法都可以让您将开发版本与昂贵的现成部署版本分开(如果我理解正确,那就是这里的目标)。 我建议选择1,因为它更干净。

希望这可以帮助!

文档不清楚

CMake的文档在这里不清楚。 CMake的Makefiles生成器会在子Makefile中创建源文件make规则,这些规则在主Makefile中不可见。 在主Makefile中,您只会找到CMake目标的PHONY规则。 我知道的唯一例外是Ninja Makefiles生成器,它将所有构建规则放入单个文件中。

将后处理步骤转换为CMake

根据我的经验-如果post_process是脚本-您可能应该考虑使用CMake脚本/在其中编写重写后处理步骤,因为CMake应该知道用于后处理的所有文件依赖项和变量(然后它将处理所有必要的重建或清理步骤)。

这是我的工作的简化/修改版本:

function(my_add_elf _target)

    set(_source_list ${ARGN})
    add_executable(${_target}_in ${_source_list})

    set_target_properties(
        ${_target}_in
        PROPERTIES
            POSITION_INDEPENDENT_CODE   0
            SUFFIX                      .elf
    )

    add_custom_command(
        OUTPUT ${_target}_step1.elf
        COMMAND some_conversion_cmd $<TARGET_FILE:${_target}_in> > ${_target}_step1.elf
        DEPENDS ${_target}_in
    )

    add_custom_target(
        ${_target}_step1 
        DEPENDS 
            ${_target}_step1.elf
    )

    add_custom_command(
        OUTPUT ${_target}_out.elf
        COMMAND final_post_process_cmd ${_target}_step1.elf > ${_target}_out.elf
        DEPENDS ${_target}_step1
    )

    add_custom_target(
        ${_target}_out 
        DEPENDS 
            ${_target}_out.elf
    )

    # alias / PHONY target
    add_custom_target(${_target} DEPENDS ${_target}_out)

endfunction(my_add_elf)

然后打电话

my_add_elf(foo foo.c)

这只是一个示例,但我希望它能给出一个主意:您可以为最终的ELF输出调用make foo为其他步骤之一调用make foo_inmake foo_step1 而且我认为所有步骤对于用户和CMake都是透明的。

无法为您的目标提供与输出之一相同的名称

当您尝试给自定义目标与其输出之一相同的名称时,例如:

add_executable(foo_in foo.c)
add_custom_command(
    OUTPUT foo_out
    COMMAND post_process foo_in > foo_out
    DEPENDS foo_in
)
add_custom_target(foo_out DEPENDS foo_out)

您最终将获得无效的make文件。 提出了一个与此有关的问题 ,希望可以通过扩展CMake本身来解决问题,并得到以下答复:

CMake不能在Makefile中产生特定的内容。 由add_custom_target创建的顶级目标名称始终是逻辑(即伪)名称。 完全不允许具有相同名称的文件。

可能的解决方法

因此,有一些解决方法,但是它们都有一个或另一个缺点。

1.最短版本:

macro(my_add_elf_we _target)
    add_executable(${_target}_in ${ARGN})
    add_custom_target(
        ${_target}_out 
        COMMAND post_process $<TARGET_FILE:${_target}_in> > ${_target}_out
        DEPENDS ${_target}_in
    ) 
    set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target}_out)
endmacro(my_add_elf_we)

您不能在add_custom_target()本身中声明OUTPUT ,但是在这种情况下,您不想这样做(因为您不希望有任何命名混乱)。 但是,如果您不声明任何输出:

  • 目标将始终被视为过时的
  • 您需要添加“不可见”输出的clean构建规则

2.强制输出名称版本

这是上面的宏版本,可将目标名称和输出名称强制为给定值:

macro(my_add_elf_in_out _target_in _target_out)
    add_executable(${_target_in} ${ARGN})
    set_target_properties(
        ${_target_in}
        PROPERTIES
            SUFFIX          ""
            OUTPUT_NAME     "${_target_in}"
    )
    add_custom_target(
        ${_target_out}
        COMMAND post_process ${_target_in} > ${_target_out}
        DEPENDS ${_target_in}
    ) 
    set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target_out})
endmacro(my_add_elf_in_out)

您用以下方式调用它:

my_add_elf_in_out(foo_in.elf foo_out.elf foo.c)

3.对象库版本

以下版本使用对象库,但是系统不会重用foo_in目标链接:

macro(my_add_elf_obj_in_out _target_in _target_out)

    add_library(${_target_in}_obj OBJECT ${ARGN})

    add_executable(${_target_in} $<TARGET_OBJECTS:${_target_in}_obj>)
    set_target_properties(
        ${_target_in}
        PROPERTIES
            SUFFIX          ""
            OUTPUT_NAME     "${_target_in}"
    )

    add_executable(${_target_out} $<TARGET_OBJECTS:${_target_in}_obj>)
    set_target_properties(
        ${_target_out}
        PROPERTIES
            SUFFIX              ""
            OUTPUT_NAME         "${_target_out}"
            EXCLUDE_FROM_ALL    1
    )
    add_custom_command(
        TARGET ${_target_out}
        POST_BUILD
        COMMAND post_process ${_target_in} > ${_target_out}
    )

endmacro(my_add_elf_obj_in_out)

4.最终版本

最后一个绝对只适用于Makefile生成器的最终版本,让我在CMake的错误跟踪器中发布了该问题:

macro(my_add_elf_ext_in_out _target_in _target_out)

    add_executable(${_target_in} ${ARGN})
    set_target_properties(
        ${_target_in}
        PROPERTIES
            SUFFIX          ""
            OUTPUT_NAME     "${_target_in}"
    )
    add_executable(${_target_out} NotExisting.c)
    set_source_files_properties(
        NotExisting.c
        PROPERTIES
            GENERATED           1
            HEADER_FILE_ONLY    1
    )
    set_target_properties(
        ${_target_out}
        PROPERTIES
            SUFFIX              ""
            OUTPUT_NAME         "${_target_out}"
            RULE_LAUNCH_LINK    "# "
    )
    add_custom_command(
        TARGET ${_target_out}
        POST_BUILD
        COMMAND post_process ${_target_in} > ${_target_out}
    )
    add_dependencies(${_target_out} ${_target_in})

endmacro(my_add_elf_ext_in_out)

一些参考

转过来的依赖项,并使用add_custom_command第二个签名 ,这应该工作:

add_custom_target(foo_out DEPENDS foo_in)
add_custom_command(TARGET foo_out POST_BUILD COMMAND post_process foo_in > foo_out)

注意:添加BYPRODUCTS foo_out将导致(例如) 忍者

多个规则生成foo_out。 涉及此目标的构建将是不正确的; 反正继续

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM