使用shell命令或globbing检索源,相应地更新构建

时间:2015-02-11 07:16:23

标签: cmake glob

如何使用任意shell命令获取CMake生成的构建系统来检索源文件并正确更新构建?

这样做的动机是从另一个构建系统迁移到CMake。中间目标是在构建系统之间共享一个源文件列表。源文件列表实际上可能存在于其他构建系统内部,但通常假设某些shell命令可以检索源文件列表。此问题与使用globbing获取源文件名的问题非常相似,但在这种情况下,手动列出CMakeLists.txt文件中的所有源文件不是一个合理的替代方法。

即使没有办法让CMake自己这样做,提供任何自动化解决方案的答案也会没问题(例如,包装生成的构建系统的脚本)。


问题的非常简单的具体示例

我们有一个由两个源文件main.cppfoo.cpp组成的应用。出于某种原因,需要使用一些shell命令获取源文件的名称,而不是将它们列在CMakeLists.txt文件中。对于此示例,文件在files.txt中每行列出一个,我们cat此文件。通常,shell命令是一些以神秘的方式检索源文件列表的脚本。

main.cpp(ver 1)

#include "foo.h"

int main() {
    foo();
}

foo.h中

#ifndef FOO_H
#define FOO_H

void foo();

#endif

Foo.cpp中

#include "foo.h"
#include <iostream>

void foo() {
    std::cout << "foo()" << std::endl;
}

files.txt(ver 1)

main.cpp
foo.cpp

的CMakeLists.txt

cmake_minimum_required(VERSION 2.8.1)
project(SourcesFromCommand)

# run some external command that retrieves our source files
execute_process(COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/files.txt OUTPUT_VARIABLE files)
# turn newline separated relative filenames into cmake list of absolute filenames
string(REPLACE "\n" ";${CMAKE_CURRENT_SOURCE_DIR}/" file_list ${files})

# print filenames to make sure the list came out right
foreach(file ${file_list})
    message(${file})
endforeach()

add_executable(main ${file_list})

CMake为包含上述文件的项目生成工作构建系统。后来,我们的应用程序成功且受欢迎,因此我们决定为ver添加新功能。 2.0。 main.cpp现在调用bar()bar.h中的bar.cpp。我们会相应更新files.txt

main.cpp(ver 2)

#include "foo.h"
#include "bar.h"

int main() {
    foo();
    bar();
}

bar.h

#ifndef BAR_H
#define BAR_H

void bar();

#endif

bar.cpp

#include "bar.h"

#include <iostream>

void bar() {
    std::cout << "bar()" << std::endl;
}

files.txt(ver 2)

main.cpp
foo.cpp
bar.cpp

以前由CMake生成的构建系统不再有效 - 尝试使用它会导致链接器错误,因为它不了解bar.cpp。这可以通过触摸CMakeLists.txt文件或重新运行cmake命令来手动解决,但构建系统的目的是让我们摆脱这种艰巨而容易被遗忘的手工劳动。如何自动化?

1 个答案:

答案 0 :(得分:1)

您可以使用touch相关CMakeLists.txt文件的makefile来解决此问题。

我将从OP的示例继续,并添加一个目录glob_us/,我们希望将所有文件名与*.cpp匹配。它包含baz.cpp,类似于OP bar.cpp

相关文件:

  • 生成文件
  • 的CMakeLists.txt
  • files.txt
  • 的main.cpp
  • main.h
  • Foo.cpp中
  • foo.h中
  • bar.cpp
  • bar.h
  • glob_us / baz.h
  • glob_us / baz.cpp

CMakeLists.txt的底部变为:

file(GLOB globbed_files glob_us/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/glob_us)

add_executable(main ${file_list} ${globbed_files})

Makefile包含以下内容:

MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

GLOBBED := $(wildcard $(MAKEFILE_DIR)/glob_us/*cpp)

# phony target that depends on whatever files we need to touch
cmake: $(MAKEFILE_DIR)/CMakeLists.txt

$(MAKEFILE_DIR)/CMakeLists.txt: $(MAKEFILE_DIR)/files.txt $(GLOBBED)
    @touch $(MAKEFILE_DIR)/CMakeLists.txt

.PHONY: cmake

生成构建系统:

mkdir build
cd build
cmake -G $MY_FAVORITE_GENERATOR ..

然后建立:

make -f ../Makefile && $MY_FAVORITE_BUILD_SYSTEM_COMMAND

文件可以添加到glob_us或从OP的示例中添加到files.txt,无需人工干预。