奇技淫巧之cmake


如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033

前言

CMake元构建系统,可以为平台首选的构建系统生成项目文件和构建脚本。例如,它可以为类Unix的系统, Ninja构建脚本, Visual Studio解决方案等生成Makefile。

https://cmake.org
https://github.com/Kitware/CMake

0.cmake常用配置及信息展示

适用于一般信息配置及展示

cmake_minimum_required(VERSION 2.8)

project(CSerialPort LANGUAGES CXX)

if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
	set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
	set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

option(BUILD_SHARED_LIBS "Build shared libraries" ON)

message(STATUS "CSerialPort CMake Info")
message(STATUS "=======================================================")
message(STATUS "    Operation System :  ${CMAKE_SYSTEM}")
message(STATUS "    CPU Architecture : ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "    Build Type : ${CMAKE_BUILD_TYPE}${CMAKE_CONFIGURATION_TYPES}")
message(STATUS "    Shared Library  : ${BUILD_SHARED_LIBS}")
message(STATUS "=======================================================")

# operating system conditional compile
if (WIN32)
    message(STATUS "Platform :  windows")
elseif(APPLE)
    message(STATUS "Platform :  apple")
elseif (UNIX)
    message(STATUS "Platform :  unix")
endif()

示例:

-- CSerialPort CMake Info
-- =======================================================
--     Operation System :  Linux-4.9.70-v7+
--     CPU Architecture : armv7l
--     Build Type : Release
--     Shared Library  : ON
-- =======================================================
-- Platform :  unix

1.mingw(gcc)生成MSVC(vs)可用的dll(.lib)

适用于msvc直接调用mingw的库

mingw(gcc)编译的动态库(DLL)默认MSVC无法调用。

CMAKE_GNUtoMS

Convert GNU import library (.dll.a) to MS format (.lib)

示例:

cmake -G "MinGW Makefiles" -DCMAKE_GNUtoMS=ON ..

注意:
也可以根据def文件手动生成msvc所需动态库

2.qt调试cmake工程

适合于qt直接编译或调试cmake的工程

  • qtcreator直接打开CMakeLists.txt工程文件
  • qmake -project可以生成qt的pro工程文件(CMakeLists.txt转换为pro)

3.cmake下载和编译其他工程

适合于编译依赖的前置库(包括非cmake工程)等

FetchContent_Declare支持git、svn、url、文件等的下载

3.1 FetchContent_MakeAvailable

CMakeLists.txt

include(FetchContent)
set(FETCHCONTENT_QUIET OFF CACHE INTERNAL "" FORCE)
FetchContent_Declare( # cmake 3.11 above
	CSerialPort
	GIT_REPOSITORY https://github.com/itas109/CSerialPort
	GIT_TAG v4.1.0
	USES_TERMINAL_DOWNLOAD TRUE
	)

FetchContent_MakeAvailable(CSerialPort) # cmake 3.14 above

# FetchContent_MakeAvailable
#message(STATUS "CSerialPort_SOURCE_DIR : ${CSerialPort_SOURCE_DIR}")
#message(STATUS "CSerialPort_BINARY_DIR : ${CSerialPort_BINARY_DIR}")

3.2 add_custom_target

CMakeLists.txt

include(FetchContent)
set(FETCHCONTENT_QUIET OFF CACHE INTERNAL "" FORCE)
FetchContent_Declare( # cmake 3.11 above
	ncurses
	GIT_REPOSITORY https://gitee.com/itas109/ncurses
	GIT_TAG v6.2 # 2020-02-12
	USES_TERMINAL_DOWNLOAD TRUE
	)
		
FetchContent_GetProperties(ncurses)
if(NOT ncurses_POPULATED)
# Fetch the content using previously declared details
FetchContent_Populate(ncurses)
endif()

add_custom_target(compile_ncurses
	COMMAND ./configure --prefix=${ncurses_BINARY_DIR}
	COMMAND make -j 8
	COMMAND make install
	COMMENT "configure, compile and install ncurses"
	WORKING_DIRECTORY ${ncurses_SOURCE_DIR}
)

add_dependencies(${PROJECT_NAME} compile_ncurses) # excute before project compile

4.安装编译文件

适合于编译完安装

CMakeLists.txt

install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/CSerialPort DESTINATION include FILES_MATCHING PATTERN "*.h")

install(TARGETS libcserialport
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib
		ARCHIVE DESTINATION lib
		)

install(FILES ${PROJECT_SOURCE_DIR}/cserialport-config.cmake.in DESTINATION lib/cmake/CSerialPort RENAME cserialport-config.cmake)

5.解决-fPIC问题

适用于解决-fPIC问题

compile flag

relocation R_X86_64_32 against `.text' can not be used when making a shared object; recompile with -fPIC

5.1 修改原始CMakeLists.txt

add_compile_options(-fPIC)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")

5.2 不修改原始CMakeLists.txt

cmake -DCMAKE_C_FLAGS="-fPIC" cmake -DCMAKE_CXX_FLAGS="-fPIC" ..

6.编译静态程序

适合于编译无依赖的程序或库

#需要在CMakeLists.txt添加以下内容

#设置静态编译
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
add_compile_options(-static)

#链接静态库
#链接gcc-g++静态库
target_link_libraries(${PROJECT_NAME} libgcc.a)
target_link_libraries(${PROJECT_NAME} libstdc++.a)
#链接网络库(windows如需要)
target_link_libraries(${PROJECT_NAME} ws2_32)
#链接线程库(必须放到最后)
target_link_libraries(${PROJECT_NAME} libpthread.a)

7.cmake直接配置与编译

适合于CI/CD,特别是Visual Studio

mkdir bin && cd bin
cmake ..
cmake --build .

8.cmake交叉编译

适用于交叉编译

通过CMAKE_TOOLCHAIN_FILE实现,无需修改原有CMakeLists.txt

cmake -DCMAKE_TOOLCHAIN_FILE=./toolchain_arm.cmake .. 

toolchain_arm.cmake

# 交叉编译的系统名称
set(CMAKE_SYSTEM_NAME Linux)
# 交叉编译的CPU架构
set(CMAKE_SYSTEM_PROCESSOR arm)

set(USER_PATH "/home/dev")

#代表了一系列的相关文件夹路径的根路径的变更,编译器到指定的根目录下寻找对应的系统库
set(CMAKE_SYSROOT ${USER_PATH}/toolchain/sysroot-linaro-eglibc-gcc4.9-2016.02-arm-linux-gnueabihf)
#set(CMAKE_FIND_ROOT_PATH ${USER_PATH}/)
# 指定主机上要安装的路径
set(CMAKE_STAGING_PREFIX ${USER_PATH}/cross_install)

#指明C和C++编译器
set(tools ${USER_PATH}/toolchain/gcc-linaro-4.9-2016.02-x86_64_arm-linux-gnueabihf)
set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)

#对FIND_PROGRAM()起作用,有三种取值,NEVER,ONLY,BOTH,第一个表示不在你CMAKE_FIND_ROOT_PATH下进行查找,第二个表示只在这个路径下查找,第三个表示先查找这个路径,再查找全局路径,对于这个变量来说,一般都是调用宿主机的程序,所以一般都设置成NEVER
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
#下面的三个选项表示只在交叉环境中查找库和头文件
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

9.检查编译器是否支持C++11

适用于使用C++11的应用

cmake_minimum_required(VERSION 2.8)

# Set the project name
project (hello_cpp11)

# try conditional compilation
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)

# check results and add flag
if(COMPILER_SUPPORTS_CXX11)#
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)#
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
    message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

# Add an executable
add_executable(hello_cpp11 main.cpp)

10.cmake生成源文件

适用于动态生成源文件

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

# Set the project name
project (cf_example)

# set a project version
set (cf_example_VERSION_MAJOR 0)
set (cf_example_VERSION_MINOR 2)
set (cf_example_VERSION_PATCH 1)
set (cf_example_VERSION "${cf_example_VERSION_MAJOR}.${cf_example_VERSION_MINOR}.${cf_example_VERSION_PATCH}")

# Call configure files on ver.h.in to set the version.
# Uses the standard ${VARIABLE} syntax in the file
configure_file(ver.h.in ${PROJECT_BINARY_DIR}/ver.h)

# Add an executable
add_executable(cf_example main.cpp)

# include the directory with the new files
target_include_directories( cf_example PUBLIC ${CMAKE_BINARY_DIR})

ver.h.in

#ifndef __VER_H__
#define __VER_H__

// version variable that will be substituted by cmake
// This shows an example using the $ variable type
const char* ver = "${cf_example_VERSION}";

#endif

main.cpp

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

int main(int argc, char *argv[])
{
    std::cout << "Hello Version " << ver << "!" << std::endl;
    return 0;
}

未完待续


License

License under CC BY-NC-ND 4.0: 署名-非商业使用-禁止演绎

如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033


Reference:
1.https://github.com/ttroy50/cmake-examples

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐