cmake 简单使用

本文介绍了一个使用CMake构建的C++ demo项目的结构与配置。详细解析了CMakeLists.txt文件中的各种指令,包括编译选项设置、源文件管理、第三方库链接等。并通过示例解释了target_link_libraries命令中PUBLIC、PRIVATE、INTERFACE参数的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cmake 构建的C++ demo 工程

  • 工程结构
./project 
 |---- my_demo/ 
 |      |---- demo.cpp
 |      `---- others.cpp
 |---- test/ 
 |      |---- test.cpp
 |      `---- CMakeLists.txt 
 |---- CMakeLists.txt 
 `---- run_build.sh 
  • CMakeLists.txt
PROJECT(my_demo)

CMAKE_MINIMUM_REQUIRED(VERSION 2.6)  

set(MY_DEMO_VERSION 3.5) 

# default C / CXX flags
set(CMAKE_C_FLAGS " -g -ggdb -O0 -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")
set(CMAKE_CXX_FLAGS " -g -ggdb -O0 -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")

set(CMAKE_C_FLAGS_DEBUG " -g -ggdb -O0 -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")
set(CMAKE_CXX_FLAGS_DEBUG " -g -ggdb -O0 -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")

set(CMAKE_C_FLAGS_RELEASE " -O3 -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")
set(CMAKE_CXX_FLAGS_RELEASE " -O3 -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")

set(CMAKE_C_FLAGS_MINSIZEREF " -Os -Wall  -fpic -fPIC -D_LARGEFILE64_SOURCE")
set(CMAKE_CXX_FLAGS_MINSIZEREF " -Os -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")

set(CMAKE_C_FLAGS_RELWITHDEBINFO " -O2 -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO " -O2 -Wall -fpic -fPIC -D_LARGEFILE64_SOURCE")

set(CMAKE_C_FLAGS_COVERAGE " ${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS_COVERAGE " ${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverag")

set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/build/${CMAKE_BUILD_TYPE}/lib)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/build/${CMAKE_BUILD_TYPE}/bin)
# name object files as xxx.o instead of xxx.cpp.o 
set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)   

# add include dirs  -> -I 
include_directories(${CMAKE_BINARY_DIR})
include_directories(${APR_INCLUDE_DIR})
include_directories(${APR_UTIL_INCLUDE_DIR})
include_directories(${MINIXML_INCLUDE_DIR})
include_directories(${CURL_INCLUDE_DIR})
include_directories(${MODULE_SDK_INCLUDE_DIR})

# add lib dirs -> -L 
#link_directories("/usr/lib64/")
link_directories(${THIRDPARTY_LIB_PATH})
link_directories(${MODULE_SDK_LIB_PATH})

message(STATUS "CPPPATH:"  
               ${APR_INCLUDE_DIR}
               ${APR_UTIL_INCLUDE_DIR} 
               ${MINIXML_INCLUDE_DIR} 
               ${CURL_INCLUDE_DIR})

message(STATUS  "LIB_PATH:${THIRDPARTY_LIB_PATH}")    
find_library(EXPAT_LIBRARY  libexpat.a) 
find_library(UUID_LIBRARY  libuuid.a ${THIRDPARTY_LIB_PATH}) 
IF (UUID_LIBRARY) 
    message(STATUS  ${UUID_LIBRARY})
else()
    message(WARN "libuuid.a not find")
endif()

# add source files 
aux_source_directory(my_demo DEMO_SRC)
message(STATUS ${DEMO_SRC})

# compile targets: libmy_demo.so and libmy_demo_static.a 
add_library(${CMAKE_PROJECT_NAME} SHARED ${DEMO_SRC})
add_library(${CMAKE_PROJECT_NAME}_static STATIC ${DEMO_SRC})

set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES VERSION ${MY_DEMO_VERSION}  SOVERSION ${MY_DEMO_VERSION})

# link static lib and all symbols -> -l 
target_link_libraries(${CMAKE_PROJECT_NAME} "-Wl,--whole-archive"  
                      ${MODULE_SDK_LIBRARY}
                      ${APR_LIBRARY}
                      ${APR_UTIL_LIBRARY}
                      ${MINIXML_LIBRARY} 
                      ${EXPAT_LIBRARY} 
                      ${UUID_LIBRARY}
                      "-Wl,--no-whole-archive")

install(TARGETS ${CMAKE_PROJECT_NAME} LIBRARY DESTINATION lib)
install(TARGETS ${CMAKE_PROJECT_NAME}_static ARCHIVE DESTINATION lib)

install(FILES
  my_demo/my_demo.h
  DESTINATION include/my_demo)

# a sub dir of this project, there is a CMakeLists.txt in it also 
add_subdirectory(test)
  • run_build.sh
#!/usr/bin/bash

CURDIR=$(cd $(dirname ${BASH_SOURCE[0]}); pwd )
rm -rf CMakeCache.txt 
rm -rf CMakeFiles 
rm -rf cmake_install.cmake

MODULE_SDK_DIR=$CURDIR/usr/local/
MODULE_DEPS_DIR=$CURDIR/third_party
THIRDPARTY_LIB_PATH=$MODULE_DEPS_DIR/lib/ 

# reset the VARS in CMakeLists.txt by command line 

cmake . -DCURL_INCLUDE_DIR=$MODULE_DEPS_DIR/include/curl -DCURL_LIBRARY=$MODULE_DEPS_DIR/lib/libcurl.so \
        -DAPR_INCLUDE_DIR=$MODULE_DEPS_DIR/include/apr-1/ -DAPR_LIBRARY=$MODULE_DEPS_DIR/lib/libapr-1.a \
        -DAPR_UTIL_INCLUDE_DIR=$MODULE_DEPS_DIR/include/apr-1/ -DAPR_UTIL_LIBRARY=$MODULE_DEPS_DIR/lib/libaprutil-1.a \
        -DMINIXML_INCLUDE_DIR=$MODULE_DEPS_DIR/include -DMINIXML_LIBRARY=$MODULE_DEPS_DIR/lib/libmxml.a \
        -DUUID_LIBRARY=$MODULE_DEPS_DIR/lib/libuuid.a \
        -DMODULE_SDK_INCLUDE_DIR=$MODULE_SDK_DIR/include/module_c_sdk \
        -DMODULE_SDK_LIBRARY=$MODULE_SDK_DIR/lib/libmodule_c_sdk_static.a \
        -DCMAKE_INSTALL_PREFIX=./usr/local/ \
        -DTHIRDPARTY_LIB_PATH=$THIRDPARTY_LIB_PATH

注:一些cmake 的Flags 也可以在命令行中修改, 如 -DCMAKE_CXX_FLAGS=fPIC


TIPS

__FILE__变成相对路径

使用cmake 编译项目,会把 __FILE__ 展开成绝对路径,形如:

[/home/admin/myworks/logging/test.cpp:74]

这样会增加不少无用文本,其实只需要相对路径就行
增加编译选项: -ffile-prefix-map=old=new 或者 -fmacro-prefix-map

refe:https://mcuoneclipse.com/2021/01/23/assert-__file__-path-and-other-cool-gnu-gcc-tricks-to-be-aware-of/

具体在CMakeLIsts.txt 中增加

add_compile_options(-fmacro-prefix-map=${CMAKE_SOURCE_DIR}=.)

结果形如:

[./test.cpp:74]

测试代码

// test.cpp 
...
std::cout << "[" << __FILE__ << "]" << std::endl;
...

A: cmake的CMakeLists里target_link_libraries PUBLIC,PRIVATE参数表示什么意思

ChatGPT3.5 Q: 在 CMakeLists.txt 文件中,target_link_libraries 命令用于指定一个或多个库文件链接到目标可执行文件或库文件中。当使用该命令时,通常需要使用 PUBLIC、PRIVATE 或 INTERFACE 关键字来指定链接的方式。这三个关键字的作用如下:

  • PUBLIC:指定库文件将被链接到目标文件中,并且该链接关系将被传递给目标文件依赖的其他目标,即链接库文件的使用者和其依赖的其他目标都将链接该库文件。例如,如果一个库文件 foo 使用了库文件 bar,那么在 foo 的 CMakeLists.txt 文件中使用 target_link_libraries(foo PUBLIC bar) 命令将同时链接 bar 到 foo 和其它使用 foo 的目标中。
  • PRIVATE:指定库文件将被链接到目标文件中,但该链接关系不会被传递给目标文件依赖的其他目标,即只有链接库文件的目标本身才会链接该库文件。例如,如果一个可执行文件 main 使用了库文件 foo,并在 main 的 CMakeLists.txt 文件中使用 target_link_libraries(main PRIVATE foo) 命令,那么只有 main 本身会链接 foo,而其它依赖于 main 的目标并不会链接 foo。
  • INTERFACE:指定库文件将不会被链接到目标文件中,但该链接关系将会被传递给目标文件依赖的其他目标,即该链接库文件的依赖目标都会链接该库文件,但目标文件本身不会链接该库文件。这种方式通常用于定义头文件库,即只提供头文件,而不提供实现文件的库。
    通过使用 target_link_libraries 命令和 PUBLIC、PRIVATE、INTERFACE 关键字,可以在 CMakeLists.txt 文件中方便地配置库文件的链接方式,从而确保程序的正确链接和运行。

可以画一个简单的图来解释 target_link_libraries 命令中的 PUBLIC、PRIVATE、INTERFACE 关键字的关系。假设有两个目标文件 main 和 libfoo,及一个库文件 libbar,它们之间的依赖关系如下图所示:

main ----> libfoo
 |           |
 +-----<-----+
       |
    libbar

在这个例子中,main 依赖于 libfoo,而 libfoo 又依赖于 libbar。

接下来,我们考虑在 main 和 libfoo 的 CMakeLists.txt 文件中使用 target_link_libraries 命令来链接库文件 libbar,并使用 PUBLIC、PRIVATE 和 INTERFACE 关键字来指定链接方式。我们分别使用红色、蓝色和绿色的箭头来表示不同的链接方式。具体如下:

target_link_libraries(main PUBLIC libbar):指定库文件 libbar 将被链接到 main 中,并且该关系将被传递给 main 依赖的其他目标。因此,使用红色箭头来表示。

main ----> libfoo
 |           |
 +-----> libbar

target_link_libraries(libfoo PRIVATE libbar):指定库文件 libbar 将被链接到 libfoo 中,但该关系不会被传递给 libfoo 依赖的其他目标。因此,只有 libfoo 本身会链接 libbar。使用蓝色箭头来表示。

main ----> libfoo
 |           |
 +-----<-----+
       |
    libbar

target_link_libraries(libfoo INTERFACE libbar):指定库文件 libbar 将不会被链接到 libfoo 中,但该关系将被传递给 libfoo 依赖的其他目标。因此,使用绿色箭头来表示。

main ----> libfoo
 |           |
 +-----<-----+
       |
    libbar

通过上述图示,我们可以更加清晰地理解 target_link_libraries 命令中的 PUBLIC、PRIVATE 和 INTERFACE 关键字的作用和区别。使用这些关键字,可以方便地控制库文件的链接方式,并保证程序的正确链接和运行。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值