代码改变世界

C/C++通用CMakeLists.txt --支持批量目标生成

2013-02-09 01:06  robturtle  阅读(11291)  评论(0编辑  收藏  举报

看了半天的手册,这个基于CMake的通用模板总算是能工作了。

实现的功能是:将CMakeLists.txt放于源代码目录,在源代码所在目录的任意一个子目录下(一般是build)执行“cmake .. && make”,将自动将所有文件中包含main函数的代码作为目标批量生成。

目前这个版本有一些缺陷,一就是build目录与源文件所在目录的相对位置是固定的,因为我习惯在源文件目录下的build目录进行创建,所以这个脚本只能在 ${SOURCE_DIR}/build 目录下生效。

另外一个缺陷就是我使用了bash命令,大致使用了egrep,cut和wc,可移植性不好。可能用纯CMake命令也能实现目前的功能,不过我目前不想再去RTFM了。

第三个缺陷正如手册中对aux_source_directory中提及的,在源目录添加新文件并不会使CMake重新配置,因为CMakeLists.txt没有被修改(事实上你一旦填写好你的外部包含路径、库路径和需要加入的库,这个列表文件将不再需要任何修改),所以你必须在添加新文件后手动更新。当然这并不会很麻烦,我宁愿手动更新一遍也不愿意为一个新的目标而去修改列表文件。

这个文件模板如下:

cmake_minimum_required (VERSION 2.6)

project (BuildAll)

# some 3rd-party/customed include/link path
include_directories (/home/jeremy/projects/include)
link_directories(/home/jeremy/projects/include 
  /home/jeremy/projects/lib)

# some options / settings
# ... #

# add external libraries
set (EXTRA_LIBS ${EXTRA_LIBS} ???}

aux_source_directory (. SRC_LIST)

# get source files holding main() function
execute_process (
  COMMAND echo ${SRC_LIST}
  COMMAND xargs egrep "main[ \t]*(.*)[ \t]*$" -l
  WORKING_DIRECTORY ..                      # NOTICE: Assumed build directory is ${SOURCE_DIR}/build, so 
# You may change the value of WORKING_DIRECTORY to suit your needs
  OUTPUT_VARIABLE TARGET_LIST
  )
string (REGEX REPLACE "\n$" "" TARGET_LIST ${TARGET_LIST})

# count number of targets
execute_process (
  COMMAND echo ${TARGET_LIST}
  COMMAND wc -l
  OUTPUT_VARIABLE TARGET_NUM
  )

# convert string from "./$1\n./$2\n..." to "$1 $2 ..."
string (REGEX REPLACE "[.]/" "" TARGET_LIST ${TARGET_LIST})
string (REGEX REPLACE "\n" " " TARGET_LIST ${TARGET_LIST})

enable_testing ()
foreach ( i RANGE 1 ${TARGET_NUM})
  execute_process (
    COMMAND echo "${TARGET_LIST}"
    COMMAND cut -d " " -f ${i}
    OUTPUT_VARIABLE SRC
  )
  string (REGEX REPLACE "\n" "" SRC ${SRC})
  string (REGEX REPLACE "[.]cpp$" ".elf" ELF ${SRC})
  add_executable (${ELF} ${SRC})
  target_link_libraries (${ELF} ${EXTRA_LIBS})
  add_test (${ELF}_Runs ${ELF})
endforeach (i)

# do sth more, like add more tests...#

之所以会想写一个这样功能的CMakeLists.txt,原因很简单,因为现在在学习阶段经常要写大量简单小巧的练习代码,为每个这样规模的代码建立一个项目或者建立一个目录显然都太过麻烦,现在有了这个文件,我就可以把所有源代码放在一块,统一生成、测试。所以我认为CMake和make之间是至少差了一个世代的,至少CMake对我来说要更加简单和智能,实现同样功能需要的代码量和RTFM时间都要少得多。

生成的目标带后缀名是个好主意,虽然很多linuxer认为Linux下二进制文件没有后缀名显得很酷很专业,但我这样选择的好处就是我可以很方便地执行像“rm *.elf  ”或者“mv *.elf  SOME/WHERE”之类的操作。