Liu Shouda coder

cmake入门

2016-07-21

CMake 为“cross platform make”的缩写。是开源的跨平台的自动化构建系统。

cmake的使用

  1. mkdir build
  2. cd build
  3. cmake ..
  4. make -j4

cmake和Makefile

Makefile 例子:

  1. OPENCV_HOME = /usr/include/opencv/
  2. DLIB_HOME = /home/sooda/tools/dlib-18.16/
  3. CC = g++ -O3
  4. CFLAG = -std=c++11
  5. LIB = -lopencv_core -lopencv_objdetect -lopencv_highgui -lopencv_imgproc -lpthread -lX11
  6. INC = -I../include/ -I$(OPENCV_HOME) -I$(DLIB_HOME)
  7. OBJ = ArgumentParser.o iris.o source.o findEyeCenter.o
  8. EXE = test_iris
  9. all: test_iris
  10. test_iris : test_iris.cpp $(OBJ)
  11. $(CC) -o $@ $@.cpp $(OBJ) $(LIB) $(INC) $(CFLAG)
  12. mv $@ ../bin/
  13. source.o: $(DLIB_HOME)dlib/all/source.cpp
  14. $(CC) -c $< $(LIB) $(INC) $(CFLAG)
  15. %.o: %.cpp ../include/%.h
  16. $(CC) -c $< $(LIB) $(INC) $(CFLAG)
  17. clean:
  18. rm -rf *.o $(EXE)

Makefile不容易跨平台,编写复杂。cmake能够自动生成makefile文件。

cmake例子

  1. cmake_minimum_required(VERSION 2.8)
  2. project(iris_segment)
  3. FIND_PACKAGE(OpenCV REQUIRED)
  4. IF (${OpenCV_VERSION} VERSION_LESS 2.3.0)
  5. MESSAGE(FATAL_ERROR "OpenCV version is not compatible : ${OpenCV_VERSION}")
  6. ENDIF()
  7. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
  8. INCLUDE_DIRECTORIES(/Users/sooda/tools/dlib-18.16)
  9. set(SOURCE_FILES
  10. iris.cpp
  11. main.cpp)
  12. add_executable(${PROJECT_NAME} ${SOURCE_FILES})
  13. TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OpenCV_LIBS})

cmake语法

  1. 变量使用${}方式取值,但是在if控制语句中是直接使用变量名
  2. 指令(参数 1 参数 2…). 参数使用括弧括起,参数之间使用空格或分号分开。
  3. 使用set设置变量。父目录设置的变量在子目录也可以直接使用。
  4. 使用add_executable来生成可执行文件,使用add_library来生成库,选项STATIC生成静态库,选项SHARED生成动态库。紧接着生成目标,使用target_link_libraries来设置依赖库。
  5. 使用ADD_SUBDIRECTORY包含子目录。
  6. 使用ADD_DEFINITIONS用来设置程序内部宏。
  7. INCLUDE_DIRECTORIES头文件搜索路径。LINK_DIRECTORIES库文件搜索路径。
  8. 使用install来发布。
  9. 使用MESSAGE输出调试信息

常用变量

  1. CMAKE_BINARY_DIR 编译路径
  2. CMAKE_CXX_FLAGS 编译选项
  3. 输出路径:
    • CMAKE_RUNTIME_OUTPUT_DIRECTORY 执行文件输出路径
    • CMAKE_ARCHIVE_OUTPUT_DIRECTORY 静态库输出路径
    • CMAKE_LIBRARY_OUTPUT_DIRECTORY 动态库输出路径
  4. CMAKE_INSTALL_PREFIX 输出文件安装位置
  5. PROJECT_SOURCE_DIR 最近使用project()命令的CMakeLists.txt所处路径
  6. AUX_SOURCE_DIRECTORY 某个目录下的所有源文件

条件判断

CMake的条件叙述为 if、elseif、else、endif。

  1. # 当 expr 值为下列其中之一时,执行 command1:
  2. # ON, 1, YES, TRUE, Y
  3. # 当 expr 值为下列其中之一时,执行 command2:
  4. # OFF, 0, NO, FALSE, N, NOTFOUND, *-NOTFOUND, IGNORE
  5. if(expr)
  6. command1(arg)
  7. else(expr)
  8. command2(arg)
  9. endif(expr)

版本较早的 CMake 要求在 else(…) 括号内必须填上对应的条件,例如

  1. if(WIN32)
  2. ...
  3. else(WIN32)
  4. command2(arg)
  5. endif(WIN32)

这种表示很容易造成误导。乍看之下会以为WIN32为TRUE时执行command2,但其实是WIN32为FALSE执行command2。在新版本中,不再强制在else处填写条件。

  1. # 以下也合法
  2. if(WIN32)
  3. ...
  4. else()
  5. command2(arg)
  6. endif()

cmake复杂项目

  1. 每个需要编译的文件夹包含一个CMakeLists。由父目录使用ADD_SUBDIRECTORY来确实是否编译该目录。
  2. 不同平台,调试或发布编译不同模块。增加变量来控制需要编译哪些模块。
  3. 核心代码和测试代码分开。核心代码编译成一个库,测试代码在外部应用该库,并测试效果。
  1. cmake_minimum_required(VERSION 2.8)
  2. project(cppmary)
  3. ADD_DEFINITIONS(-DLOGGING_LEVEL=LL_DEBUG)
  4. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
  5. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
  6. set(CMAKE_DEBUG_POSTFIX d)
  7. INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/3rdparty
  8. ${PROJECT_SOURCE_DIR}/include)
  9. set(build_ios false)
  10. if (build_ios)
  11. set(build_demo_module false)
  12. set(build_gtest_module false)
  13. else()
  14. set(build_demo_module true)
  15. set(build_gtest_module true)
  16. set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
  17. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
  18. endif()
  19. set(build_gtest_module false)
  20. set(build_one_lib false)
  21. ADD_SUBDIRECTORY(3rdparty)
  22. ADD_SUBDIRECTORY(src)
  23. if (build_demo_module)
  24. ADD_SUBDIRECTORY(test)
  25. ADD_SUBDIRECTORY(examples)
  26. endif()
  27. set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/release/)
  28. install(DIRECTORY include/ DESTINATION include
  29. FILES_MATCHING PATTERN "*.h*")
  30. install(DIRECTORY 3rdparty DESTINATION include
  31. FILES_MATCHING PATTERN "*.h*")
  32. install(DIRECTORY data/ DESTINATION data)

cmake 发布

编译完之后,需要把include文件,lib文件,模型文件整合到一个文件夹。如果都是手动操作,很繁琐。容易出错。cmake支持自动发布。

####使用install发布

  1. set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/release/)
  2. install(DIRECTORY include/ DESTINATION include
  3. FILES_MATCHING PATTERN "*.h*")
  4. install(DIRECTORY 3rdparty DESTINATION include
  5. FILES_MATCHING PATTERN "*.h*")
  6. install(DIRECTORY data/ DESTINATION data)

CMAKE_INSTALL_PREFIX设置发布路径。

需要注意的是,install(DIRECTORY data/ DESTINATION data)中,’data/‘’的‘/’不能去掉。这句表示讲data下的所有文件拷贝到目标路径下的data目录。如果把’/’去掉会多一层目录’data/data/xxx’。这个规则和rsync一致。

使用copy发布

也可以使用copy来进行文件移动。

  1. file(GLOB files "lib/local/LandmarkDetector/model/*.txt")
  2. foreach(file ${files})
  3. if (MSVC)
  4. file(COPY ${file} DESTINATION ${CMAKE_BINARY_DIR}/bin/Debug/model)
  5. file(COPY ${file} DESTINATION ${CMAKE_BINARY_DIR}/bin/Release/model)
  6. else(MSVC)
  7. file(COPY ${file} DESTINATION ${CMAKE_BINARY_DIR}/bin/model)
  8. endif(MSVC)
  9. endforeach()

以上两种发布方式的区别在于,使用install发布,只有在build目录下,使用make install才生效。使用copy则在编译的时候就生效。前者在xcode等ide下编译,可能比较不好处理。

ios交叉编译

编译到ios需要下载对应的配置文件:IOS.cmake 具体方法:

选择平台类型,编译器

选择IOS.cmake

configure,generate

设置编译类型

设置调试符号

设置输出路径


上一篇 智能指针用法

下一篇 idlak笔记