取决于命令输出的cmake规则

时间:2019-06-11 16:16:51

标签: cmake

当且仅当需要重新生成源文件时,如何在预生成步骤中生成源文件?

我项目的依赖项之一是库(libfoo),该库重新链接的成本很高(几分钟),而重建成本甚至更高(不到一个小时)。生成这种依赖关系的源文件是廉价的(几秒钟),但是使用过时的源将导致生成的应用程序套件无用。我有一个命令check_foo.sh,当必须重新生成源代码时,它将以非零状态退出,但是我无法确定如何说服CMake在每次构建过程中仅运行check_foo.shlibfoo返回非零时,重新构建check_foo.sh

在尝试创建一个简单的证明时,尽管只运行一次generate_foo_if.sh,但我得到的最接近的证明如下。最终目标是generate_foo_if.sh无条件运行,但是libfoo仅在generate_foo_if.sh修改foo.cpp时重建。

CMakeLists.txt

cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(my_project
        VERSION 1.0.0.0
        LANGUAGES CXX)
add_custom_command(OUTPUT foo.cpp
                   COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/generate_foo_if.sh" "${CMAKE_CURRENT_BINARY_DIR}/foo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/check_foo.sh"
                   WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
                   COMMENT "Generating foo.cpp..."
                  )
add_library(foo STATIC foo.cpp)
add_executable(main main.cpp)
target_link_libraries(main foo)

main.cpp

#include "foo.hpp"
int main(int,char**){
    return foo::exit_status;
}

foo.hpp

#pragma once
namespace foo {
extern const int exit_status;
}

check_foo.sh

#!/usr/bin/env bash
exit $(((${RANDOM} % 2 )))

generate_foo_if.sh

#!/usr/bin/bash
CHECK=${2:-./check_foo.sh}
if [ ${CHECK} -eq 0 ]; then
    exit 0
fi
msg=$(cat <<__EOF
#include "foo.hpp"
namespace foo {
const int exit_status = 1;
}
__EOF
)
echo "${msg}" >${1:-foo.cpp}

1 个答案:

答案 0 :(得分:0)

结果证明,我离目标不远。

关键的区别似乎在于使用BYPRODUCTS而不是OUTPUT创建自定义目标而不是自定义命令,并显式添加依赖项。更新的CMakeLists.txt如下,并导致所需的行为(即libfoo仅在应有的情况下重新生成)。

cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(my_project
    VERSION 1.0.0.0
    LANGUAGES CXX)
add_custom_target(generate_foo
              COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/generate_foo_if.sh"  "${CMAKE_CURRENT_BINARY_DIR}/foo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/check_foo.sh"
              WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
              BYPRODUCTS foo.cpp
             )
add_library(foo STATIC foo.cpp)
add_dependencies(foo generate_foo)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
add_executable(main main.cpp)
target_link_libraries(main foo)

虽然我不能说我真的知道为什么为什么,但这确实满足了我的要求。