我以前的帖子解释Cmake是如何管理一个简单的项目(只包含一个定义和实现文件)。现在,我们可以在一个复杂的项目看,含有一个共同的共享库,示例和单元测试。在这种情况下,而不是一个愚蠢的HelloWorld项目,我选择了Itemviews-NG的项目,这是一个实验性项目,由Qt实验室主办,并且目前使用qmake作为构建系统。该项目本身包含以下内容:
n 共享库包含一个共同的基类;
n 库的每一个类实例的集合;
n 库的每一个类单元测试集合;
注意:文档将不被创建了 -Itemview- NG使用qdoc生成文档,AFAIK还没有很好地和CMake整合呢。这儿有另外一个替代,在Cmake中使用doxygen,连同lcov封面和gcov HTML输出相结合。
作为一个起点,该项目本身包含了需要由MOC处理各种文件。为了简化这个过程中,可以使用CMake的工具,它会使用automoc工具自动找到所需的文件进行预处理,并包含它们在目标编译中。 Qt库和包含文件也提供了的Qt4 cmake的包(内置)。要使用的Qt4加automoc CMake的软件包,你可以包括在项目上的根目录下的CMakeFiles.txt以下代码:
# Qt4 package is mandatory
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
# Automoc4 is also mandatory
find_package(Automoc4 REQUIRED)
现在让我们看看src目录CMakeFiles.txt的变化
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Create a variable containing a list of all implementation files
file(GLOB itemviews-ng_SOURCES *.cpp)
# The same applies for headers which generates MOC files (excluding private implementation ones)
file(GLOB itemviews-ng HEADERS *[^_p].h)
# Now the magic happens: The function below is responsible for generating the MOC files)
automoc4_moc_headers(itemviews-ng ${itemviews-ng_HEADERS})
# Creates a target itemviews-ng which creates a shard library with the given sources
automoc4_add_library(itemviews-ng SHARED ${itemviews-ng_SOURCES})
# Tells the shared library to be linked against Qt ones
target_link_libraries(itemviews-ng ${QT_LIBRARIES})
# Installs the header files into the {build_dir}/include/itemviews-ng directory
install(FILES ${itemviews-ng_HEADERS} DESTINATION include/itemviews-ng)
# Installs the target file (libitemviews-ng.so) into the {build_dir}/lib directory
install(TARGETS itemviews-ng LIBRARY DESTINATION lib)
现在,该项目使用的每一个例子或测试可以使用目标itemviews-ng作为联系的依赖。由于每个例子和测试是在一个类似的方法编译,我们可以使用函数从而简化编译过程。以下是这些函数的例子:
function(example example_NAME example_SOURCES example_HEADERS)
automoc4_moc_headers(${example_NAME}_example ${examples_HEADERS})
# The third argument (resource files) is optional:
set(example_RESOURCES ${ARGV3})
if(example_RESOURCES)
automoc4_add_executable(${example_NAME}_example
${example_SOURCES} {example_RESOURCES})
else(example_RESOURCES)
automoc4_add_executable(${example_NAME}_example
${example_SOURCES}) endif(example_RESOURCES)
target_link_libraries(${example_NAME}_example itemviews-ng
{QT_LIBRARIES})
endfunction(example)
function(test test_NAME test_SOURCES)
set(test_RESOURCES ${ARGV2})
if(test_RESOURCES)
automoc4_add_executable(${test_NAME}_test
{test_SOURCES} ${test_RESOURCES})
else(test_RESOURCES)
automoc4_add_executable(${test_NAME}_test
${test_SOURCES}) endif(test_RESOURCES)
target_link_libraries(${test_NAME}_test itemviews-ng
${QT_LIBRARIES})
include_directories(${itemviews-ng_BINARY_DIR}/tests/${test_NAME})
add_test(${test_NAME} ${test_NAME}_test)
add_dependencies(check ${test_NAME}_test)
endfunction(test)
上述功能可以插入到.cmake文件中(如:InternalMacros.cmake)。这就需要cmake的/ modules目录中去找。要加载它,在根目录的CMakeLists.txt加上以下行:
include(InternalMacros)
现在,你创建的每一个例子的CmakeLists.txt 像这样:
set(mycustomexample_SOURCES mycustomexample.cpp main.cpp )
set(mycustomexample_HEADERS mycustomexample.h )
example(mycustomexample "${mycustomexample_SOURCES}" "${mycustomexample_HEADERS}")
这同样适用于测试:
test(mycustomtest "${mycustomtest_SOURCES}")
我已经在我的个人gitorious网站itemviews-ng clone上创建一个cmake分支。你可以看看,看看如何解释上面的代码的行为。
附:原文及原文地址: