CMAKE&Make

  1. aux_source_directory
  2. CMAKE和MAKE之间的区别
  3. find_package
  4. 相关原理
  5. include_directory

aux_source_directory

今天clion写项目 遇到一个问题 明明写了aux_source_directory 却依然提示没有加入. 后来查了下, 并不推荐使用那个命令.
可能会存在一些问题

https://cmake.org/cmake/help/latest/command/aux_source_directory.html

# 必须片段
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cc)

# 多文件
# 如果一味地在add_executable中添加源文件, 会导致太长了
# 将dir目录中所有源文件保存在变量中
aux_source_directory(. DIR_SOURCE)
# 将变量赋值给Demo
add_executable(Demo ${DIR_SOURCE})

# 多文件多目录
# 需要在主目录和子文件夹中都编写CMakeLists.txt文件

# 主文件添加子目录
add_subdirectory(dir1)
# 添加链接库
target_link_libraries(Demo Foo)

# dir1目录中
aux_source_directory(. DIR1_SOURCE)
# 生成链接库 Foo 在主文件中添加即可
add_library(Foo ${DIR1_SOURCE})

CMAKE和MAKE之间的区别

博客原文

自己的理解
通过为cmake编写CMakeList文件, cmake即可按照规则生成相应的Makefile文件
然后make读取Makefile文件就可以按照规则将源代码编译

总的来说cmake就是为make生成Makefile文件, (Makefile文件可以自己编写, 也可以用Cmake生成)
应该是编写CMakeList的代码量少于或者简单于Makefile, 简化了操作

find_package

https://zhuanlan.zhihu.com/p/97369704

https://www.jianshu.com/p/a0915895dbbc

find_package 存在两个模式

  • module模式
  • config模式
find_package(GLEW REQUIRED) # 先module模式再config模式

find_package(GLEW REQUIRED CONFIG) # 使用config模式

module模式

find_package(GLEW REQUIRED)
if (GLEW_FOUND)
    message("cannot find glew")
endif()

通过上述命令查找glew库,首先会去cmake的modules目录下查找对应的cmake文件。

glew对应的cmake文件为FindGLEW.cmake

C:/Application/Code/cmake-3.19.0-rc2-win64-x64/share/cmake-3.19/Modules/FindGLEW.cmake

config模式

如果module模式对应的cmake文件不存在则启动config模式。

config模式会在如下目录搜索对应的配置文件glew-config.cmakeGLEWConfig.cmake

W代表windows平台 U代表unix平台

<prefix>/                                                       (W)
<prefix>/(cmake|CMake)/                                         (W)
<prefix>/<name>*/                                               (W)
<prefix>/<name>*/(cmake|CMake)/                                 (W)
<prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/                 (U)
<prefix>/(lib/<arch>|lib*|share)/<name>*/                       (U)
<prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/         (U)
<prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/         (W/U)
<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/               (W/U)
<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/ (W/U)

prefix生成规则如下

  1. 查找GLEW_ROOT的cmake变量
  2. 使用命令行cmake -DCMAKE_PREFIX_PATH=/tmp/test
  3. 特定的cmake变量如GLEW_DIR CMAKE_PREFIX_PATH
# glew-config.cmake

find_path(GLEW_INCLUDE_DIR glew/include/)
find_library(GLEW_LIBRARY NAMES glew32 PATHS glew/lib/Release/x64)

if (GLEW_INCLUDE_DIR AND GLEW_LIBRARY)
    set(GLEW_FOUND TRUE)
endif()

相关原理

## CMake根目录生成Makefile

# 使用all走这里
all: cmake_check_build_system
    $(CMAKE_COMMAND) -E cmake_progress_start /tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles /tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles/progress.marks
    $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all
    $(CMAKE_COMMAND) -E cmake_progress_start /tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles 0
.PHONY : all

# 直接使用目标untitled4
untitled4: cmake_check_build_system
    $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 untitled4
.PHONY : untitled4


## CMakeFiles/Makefile2
# Convenience name for target.
untitled4: CMakeFiles/untitled4.dir/rule
.PHONY : untitled4

# Build rule for subdir invocation for target.
CMakeFiles/untitled4.dir/rule: cmake_check_build_system
    $(CMAKE_COMMAND) -E cmake_progress_start /tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles 3
    $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 CMakeFiles/untitled4.dir/all
    $(CMAKE_COMMAND) -E cmake_progress_start /tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles 0
.PHONY : CMakeFiles/untitled4.dir/rule

# All Build rule for target.
CMakeFiles/untitled4.dir/all:
    $(MAKE) $(MAKESILENT) -f CMakeFiles/untitled4.dir/build.make CMakeFiles/untitled4.dir/depend
    $(MAKE) $(MAKESILENT) -f CMakeFiles/untitled4.dir/build.make CMakeFiles/untitled4.dir/build
    @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --progress-dir=/tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles --progress-num=1,2,3 "Built target untitled4"
.PHONY : CMakeFiles/untitled4.dir/all


##Shell
# 生成depend
$ make -f CMakeFiles/untitled4.dir/build.make CMakeFiles/untitled4.dir/depend
Scanning dependencies of target untitled4
# 变更文件
./CMakeFiles/untitled4.dir/depend.internal
./CMakeFiles/untitled4.dir/depend.make
./CMakeFiles/untitled4.dir/CXX.includecache
# 构建
$make -f CMakeFiles/untitled4.dir/build.make CMakeFiles/untitled4.dir/build
[100%] Building CXX object CMakeFiles/untitled4.dir/Base.cpp.o
[100%] Linking CXX executable untitled4
# ./CMakeFiles/untitled4.dir/depend.internal
CMakeFiles/untitled4.dir/Base.cpp.o
 /tmp/tmp.3r11cPofBP/Base.cpp
 /tmp/tmp.3r11cPofBP/Base.h
CMakeFiles/untitled4.dir/main.cpp.o
 /tmp/tmp.3r11cPofBP/Base.h
 /tmp/tmp.3r11cPofBP/main.cpp

# ./CMakeFiles/untitled4.dir/depend.make
CMakeFiles/untitled4.dir/Base.cpp.o: ../Base.cpp
CMakeFiles/untitled4.dir/Base.cpp.o: ../Base.h

CMakeFiles/untitled4.dir/main.cpp.o: ../Base.h
CMakeFiles/untitled4.dir/main.cpp.o: ../main.cpp
# 生成依赖
CMakeFiles/untitled4.dir/depend:
    cd /tmp/tmp.3r11cPofBP/cmake-build-debug && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /tmp/tmp.3r11cPofBP /tmp/tmp.3r11cPofBP /tmp/tmp.3r11cPofBP/cmake-build-debug /tmp/tmp.3r11cPofBP/cmake-build-debug /tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles/untitled4.dir/DependInfo.cmake --color=$(COLOR)
.PHONY : CMakeFiles/untitled4.dir/depend

# 构建
CMakeFiles/untitled4.dir/build: untitled4
.PHONY : CMakeFiles/untitled4.dir/build

untitled4: CMakeFiles/untitled4.dir/main.cpp.o
untitled4: CMakeFiles/untitled4.dir/Base.cpp.o
untitled4: CMakeFiles/untitled4.dir/build.make
untitled4: CMakeFiles/untitled4.dir/link.txt
    @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Linking CXX executable untitled4"
    $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/untitled4.dir/link.txt --verbose=$(VERBOSE)


CMakeFiles/untitled4.dir/main.cpp.o: CMakeFiles/untitled4.dir/flags.make
CMakeFiles/untitled4.dir/main.cpp.o: ../main.cpp
    @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/tmp/tmp.3r11cPofBP/cmake-build-debug/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building CXX object CMakeFiles/untitled4.dir/main.cpp.o"
    /usr/bin/g++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/untitled4.dir/main.cpp.o -c /tmp/tmp.3r11cPofBP/main.cpp

CMake识别变更和重新编译,是通过比对冒号左右两个文件的最后修改时间。
A:B A依赖B,如果B的修改时间晚于A说明A需要重新构建。

set(CurrentProtoGenP2P ${P2P_OUT_PATH_PATH}/${ProtoName}.proto.tars_Api.p2p.h)
add_custom_command(OUTPUT ${CurrentProtoGenP2P}
  COMMAND sh -c "python2 ${P2P_SELECT_AND_BUILD} ${P2P_OUT_PATH_PATH} ${AllDirs} ${PROTOBUF_ROOT}/include/include ${Protoc} ${ProtoFile}"
  DEPENDS ${Protoc} ${ProtoFile}
  WORKING_DIRECTORY ${Dir})
list(APPEND Srcs ${CurrentProtoGenP2P})

include_directory

搜寻头文件的顺序

  1. “<>” -I指定的路径, 系统路径
  2. “""“ 当前路径, -I指定的路径, 系统路径
  3. CMake中include_directory对应-I
  4. GCC搜索头文件顺序
    1. “""“, 搜索当前路径
    2. “""“, 搜索-iquote
    3. 搜索-I
    4. 搜索-isystem
    5. 系统路径
    6. -idirafter
function(add_unique list_var element)
   # 获取当前列表
   set(current_list ${${list_var}})

   # 检查元素是否已经在列表中
   list(FIND current_list ${element} index)
   if(index EQUAL -1)
      # 如果元素不在列表中,添加它
      list(APPEND current_list ${element})
      # 更新原始列表变量
      set(${list_var} ${current_list} PARENT_SCOPE)
   endif()
endfunction()

foreach(include_dir ${include_dirs})
   message("add dir ${include_dir}")
   include_directories(${include_dir})
endforeach()

function(include_directories_recursively base_dir dst)
    # 获取当前目录的所有子目录
    set(include_dirs)
    file(GLOB_RECURSE header_files "${base_dir}/*.h" "${base_dir}/*.hpp")
    foreach(header_file ${header_files})
        get_filename_component(header_dir ${header_file} DIRECTORY)
        add_unique(include_dirs "-idirafter ${header_dir}")
    endforeach()
    string(REPLACE ";" " " include_dirs "${include_dirs}")
    set(${dst} "${${dst}} ${include_dirs}" PARENT_SCOPE)
endfunction()

set(DIR_AFTER)
include_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR} DIR_AFTER)
include_directories_recursively(${PUBINCLUDE} DIR_AFTER)
message("${DIR_AFTER}")
  1. idirafter 能不能起作用
  2. 为什么Make没问题
function(add_unique list_var element)
    # 获取当前列表
    set(current_list ${${list_var}})
    # 检查元素是否已经在列表中
    list(FIND current_list ${element} index)
    if(index EQUAL -1)
        # 如果元素不在列表中,添加它
        list(APPEND current_list ${element})
        # 更新原始列表变量
        set(${list_var} ${current_list} PARENT_SCOPE)
    endif()
endfunction()

function(include_directories_recursively base_dir dst)
    # 获取当前目录的所有子目录
    set(include_dirs)
    file(GLOB_RECURSE header_files "${base_dir}/*.h" "${base_dir}/*.hpp")
    foreach(header_file ${header_files})
        get_filename_component(header_dir ${header_file} DIRECTORY)
        add_unique(include_dirs "-idirafter ${header_dir}")
    endforeach()
    string(REPLACE ";" " " include_dirs "${include_dirs}")
    set(${dst} "${${dst}} ${include_dirs}" PARENT_SCOPE)
endfunction()

set(DIR_AFTER)
include_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR} DIR_AFTER)
include_directories_recursively(${PUBINCLUDE} DIR_AFTER)
message("${DIR_AFTER}")

set(SVR_NAME "NewMainSvr")
message("server name ${SVR_NAME}")

file(GLOB_RECURSE PRJ_SRCS "*.cpp" "*.c")
#添加目标
add_library(${SVR_NAME} SHARED ${PRJ_SRCS})
#链接库
target_link_libraries(${SVR_NAME} ${COMMON_LIBS})
target_link_libraries(${SVR_NAME} "i18n")
set_target_properties(${SVR_NAME} PROPERTIES COMPILE_FLAGS "-D__HIGH_PERFORMANCE__ ${COMMON_CPP_FLAGS} ${DIR_AFTER}")