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 关键字的作用和区别。使用这些关键字,可以方便地控制库文件的链接方式,并保证程序的正确链接和运行。