CMake:Example
CMake 사용 예제를 정리한다.
Install preefix
make install단계에 적용할, 프로그램 또는 라이브러리를 설치할 디렉토리를 적용할 수 있다.
Print verbose
빌드 중 상세정보(명령행 등)를 보고싶을 경우 아래와 같이 VERBOSE
옵션을 추가하면 된다.
중요한 점은 cmake
가 아닌, make
단계에서 적용하는 것이다.
Print variables
아래와 같이 사용하면 CMakeLists.txt
에서 사용할 수 있는 모든 변수 목록이 출력된다.
CMake Script Mode
CMake 빌드가 아닌, 스크립트 단위로 사용하고자 할 경우 아래와 같이 -P
옵션을 적용하면 된다.
Check directory exists
Global property
You can 'simulate' GLOBAL variable behavior, by using properties with GLOBAL scope :
Then you can extract your global property by using
Target property
I've tried GET_TARGET_PROPERTY but it does not work. The SUFFIX property returns NOTFOUND unless we explicitly set it by calling SET_TARGET_PROPERTIES. Take the following CMakeLists.txt as an example:
PROJECT(hello)
ADD_LIBRARY(hello SHARED hello.c)
GET_TARGET_PROPERTY(suffix hello SUFFIX)
MESSAGE("suffix = ${suffix}")
SET_TARGET_PROPERTIES(hello PROPERTIES SUFFIX .so)
GET_TARGET_PROPERTY(suffix hello SUFFIX)
MESSAGE("suffix = ${suffix}")
Library version
Custom Command
- CMake » 3.0.2 Documentation » cmake-commands(7) » add_custom_command
- CMake » 3.0.2 Documentation » cmake-commands(7) » add_custom_target
- Stackoverflow: cmake, add_custom_command with dependencies from a different directory
- Stackoverflow: How to make CMake target executed whether specified file was changed?
cmake_minimum_required(VERSION 2.8 )
project(part)
# ...
add_custom_command(OUTPUT part.out
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/part.src part.out
DEPENDS part.src)
add_custom_target(part_out
DEPENDS part.out)
Check machine
머신 아키텍처(32bit or 64bit)는 아래와 같이 확인할 수 있다.
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set (BOOST_LIBRARY "/boost/win64/lib")
else ()
set (BOOST_LIBRARY "/boost/win32/lib")
endif ()
set (CMAKE_EXE_LINKER_FLAGS ${BOOST_LIBRARY})
Linker flags
whole-archive
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set (MAIN_LINK -Wl,-force_load ${MAIN_STATIC})
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set (MAIN_LINK -Wl,--whole-archive ${MAIN_STATIC} -Wl,--no-whole-archive)
endif ()
# ...
target_link_libraries (${MAIN_SHARED} ${MAIN_LINK})
CMake RPATH handling
- See also: rpath, install_name
- [추천] CMake RPATH handling 1
- Stackoverflow: How can LD_LIBRARY_PATH be changed within CMake?
- [추천] RPATH handling 2
- Stackoverflow: CMAKE RPATH not working - could not find shared object file
아래와 같이 적용하면 된다.
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
add_library(heart SHARED ${HEART_FILES})
add_executable(run ${RUN_FILES})
target_link_libraries(run heart)
install(
TARGETS heart run
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
)
단, add_library
, add_executable
과 같이 타겟을 생성하는 타이밍 보다 먼저 호출되어야 한다. (target_link_libraries
같은 함수도 포함되는지 확인 필요)
Static & Shared library
- Make Both Static and Shared Libraries in One Build with CMake
- Stackoverflow: Is it possible to get CMake to build both a static and shared version of the same library?
- Stackoverflow: CMake: how create a single shared library from all static libraries of subprojects?
- Build shared and static in one build
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
# On Linux, it will build MyLib.a and MyLib.so
CUDA Example
- CMake » 3.0.2 Documentation » cmake-modules(7) » FindCUDA
- Example of CMake File for CUDA+CPP Code
- How to build CUDA programs using CMake
- [추천] Compiling .cu with Mpi, Gcc and Cmake
google-protocol-buffers custom target example
Protobuf를 사용하기 위한 사용자정의 빌드방법.
## CMake google-protocol-buffers build script.
exists_define_or_die (THIRD_PREFIX)
set (PROTOBUF_TARGET_NAME "protobuf")
project (${PROTOBUF_TARGET_NAME})
set (PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set (PROTOBUF_DIR "${PARENT_DIR}/protobuf")
#set (PROTOBUF_AUTOGEN "${PROTOBUF_DIR}/autogen.sh")
set (PROTOBUF_CONFIG "${PROTOBUF_DIR}/configure")
set (PROTOBUF_MAKE "${PROTOBUF_DIR}/Makefile")
set (PROTOBUF_LIB_TARGET "${THIRD_PREFIX}/lib/libprotobuf.a")
set (PROTOBUF_EXE_TARGET "${THIRD_PREFIX}/bin/protoc")
add_custom_command (OUTPUT ${PROTOBUF_DIR}
COMMAND git clone --depth=1 https://github.com/google/protobuf.git
WORKING_DIRECTORY ${PARENT_DIR}
)
add_custom_command (OUTPUT ${PROTOBUF_CONFIG}
COMMAND ./autogen.sh
DEPENDS ${PROTOBUF_DIR}
WORKING_DIRECTORY ${PROTOBUF_DIR}
)
add_custom_command (OUTPUT ${PROTOBUF_MAKE}
COMMAND ./configure --prefix=${THIRD_PREFIX}
DEPENDS ${PROTOBUF_CONFIG}
WORKING_DIRECTORY ${PROTOBUF_DIR}
)
add_custom_command (OUTPUT ${PROTOBUF_LIB_TARGET} ${PROTOBUF_EXE_TARGET}
COMMAND make && make install
DEPENDS ${PROTOBUF_MAKE}
WORKING_DIRECTORY ${PROTOBUF_DIR}
)
add_custom_target (${PROTOBUF_TARGET_NAME}
DEPENDS ${PROTOBUF_LIB_TARGET} ${PROTOBUF_EXE_TARGET}
)
# ...
add_dependencies (MAIN_PROJ protobuf)
Script mode example
스크립트 모드 예제:
## CMake third-party library generator.
cmake_minimum_required (VERSION 2.8.8)
set (THIRD_ARCHIVE "${CMAKE_CURRENT_SOURCE_DIR}/libthird.a")
set (THIRD_OBJS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/objs")
if (EXISTS ${THIRD_OBJS_DIR})
file (REMOVE_RECURSE ${THIRD_OBJS_DIR})
endif ()
if (NOT EXISTS ${THIRD_OBJS_DIR})
file (MAKE_DIRECTORY ${THIRD_OBJS_DIR})
endif ()
# Extract object in the archive.
foreach (LIB_CURSOR ${THIRD_LIBS})
execute_process (
COMMAND ar xv "${LIB_CURSOR}"
WORKING_DIRECTORY "${THIRD_OBJS_DIR}"
)
endforeach ()
execute_process (
COMMAND ar cr "${THIRD_ARCHIVE}" *.o
WORKING_DIRECTORY "${THIRD_OBJS_DIR}"
)
아래와 같이 실행하면 된다.
Print all properties
I have had limited success with the following work-around to the apparent lack of ability to dynamically query for the properties of a target.
I invoke the cmake command to list all properties, and then try each one on the target.
# Get all propreties that cmake supports
execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST)
# Convert command output into a CMake list
STRING(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
STRING(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}")
function(print_properties)
message ("CMAKE_PROPERTY_LIST = ${CMAKE_PROPERTY_LIST}")
endfunction(print_properties)
function(print_target_properties tgt)
if(NOT TARGET ${tgt})
message("There is no target named '${tgt}'")
return()
endif()
foreach (prop ${CMAKE_PROPERTY_LIST})
string(REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" prop ${prop})
# message ("Checking ${prop}")
get_property(propval TARGET ${tgt} PROPERTY ${prop} SET)
if (propval)
get_target_property(propval ${tgt} ${prop})
message ("${tgt} ${prop} = ${propval}")
endif()
endforeach(prop)
endfunction(print_target_properties)
정적 라이브러리의 메인 함수 제거 방법
dwm의 main
을 제거하고 나만의 main
함수를 추가하는 방법. strip 유틸리티를 사용하면 된다.
cmake_minimum_required (VERSION 3.3)
project (opwm)
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
set (DWM_NAME dwm)
set (DWM_VERSION 6.2)
set (DWM_SOURCE_FILES
dwm/drw.c
dwm/dwm.c
dwm/util.c)
set (OPWM_NAME opwm)
set (OPWM_VERSION 6.2)
set (OPWM_SOURCE_FILES
main.c)
set (DWM_NOMAIN_NAME dwm-nomain)
set (DWM_NOMAIN_PATH
"${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}dwm-nomain${CMAKE_STATIC_LIBRARY_SUFFIX}")
set (COMMON_COMPILE_DEFINITIONS
_DEFAULT_SOURCE
_BSD_SOURCE
_POSIX_C_SOURCE=2
XINERAMA)
set (COMMON_INCLUDE_DIRECTORIES
/usr/X11R6/include
/usr/include/freetype2
${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/dwm)
set (COMMON_COMPILE_OPTIONS
-std=c99
-pedantic
-Wall
-Wno-deprecated-declarations)
set (COMMON_LINK_LIBRARIES
-L/usr/X11R6/lib
-lX11
-lXinerama
-lfontconfig
-lXft)
add_library (${DWM_NAME} STATIC ${DWM_SOURCE_FILES})
target_compile_definitions (${DWM_NAME} PRIVATE ${COMMON_COMPILE_DEFINITIONS} VERSION=\"${DWM_VERSION}\")
target_include_directories (${DWM_NAME} PRIVATE ${COMMON_INCLUDE_DIRECTORIES})
target_compile_options (${DWM_NAME} PRIVATE ${COMMON_COMPILE_OPTIONS})
add_custom_target (
${DWM_NOMAIN_NAME}
ALL
DEPENDS ${DWM_NOMAIN_PATH})
add_custom_command (
OUTPUT ${DWM_NOMAIN_PATH}
COMMAND strip --strip-symbol=main -o "${DWM_NOMAIN_PATH}" "$<TARGET_FILE:${DWM_NAME}>"
DEPENDS ${DWM_NAME}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_executable (${OPWM_NAME} ${OPWM_SOURCE_FILES})
add_dependencies (${OPWM_NAME} ${DWM_NOMAIN_NAME})
target_compile_definitions (${OPWM_NAME} PRIVATE ${COMMON_COMPILE_DEFINITIONS})
target_include_directories (${OPWM_NAME} PRIVATE ${COMMON_INCLUDE_DIRECTORIES})
target_compile_options (${OPWM_NAME} PRIVATE ${COMMON_COMPILE_OPTIONS})
target_link_libraries (${OPWM_NAME} PRIVATE ${DWM_NOMAIN_PATH} ${COMMON_LINK_LIBRARIES})
set (COMPILE_COMMANDS_NAME cc)
set (COMPILE_COMMANDS_SRC "${CMAKE_BINARY_DIR}/compile_commands.json")
set (COMPILE_COMMANDS_DEST "${CMAKE_SOURCE_DIR}/compile_commands.json")
add_custom_target (${COMPILE_COMMANDS_NAME} DEPENDS ${COMPILE_COMMANDS_DEST})
add_custom_command (
OUTPUT ${COMPILE_COMMANDS_DEST}
COMMAND ${CMAKE_COMMAND} -E copy "${COMPILE_COMMANDS_SRC}" "${COMPILE_COMMANDS_DEST}"
DEPENDS ${OPWM_NAME} ${COMPILE_COMMANDS_SRC}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
install (TARGETS ${OPWM_NAME})