[c++] 가장 간단하지만 완전한 CMake 예제

어떻게 든 CMake가 작동하는 방식에 완전히 혼란 스럽습니다. CMake가 작성되는 방식을 이해하는 데 가까워 질 때마다 내가 읽은 다음 예제에서 사라집니다. 내가 알고 싶은 것은 내 프로젝트를 어떻게 구성해야하는지, 그래서 내 CMake는 앞으로 최소한의 유지 관리를 필요로한다는 것입니다. 예를 들어, 다른 모든 src 폴더와 똑같이 작동하는 src 트리에 새 폴더를 추가 할 때 CMakeList.txt를 업데이트하고 싶지 않습니다.

이것이 내 프로젝트의 구조를 상상하는 방법이지만 이것은 단지 예일뿐입니다. 권장 방법이 다른 경우, 방법을 알려주십시오.

myProject
    src/
        module1/
            module1.h
            module1.cpp
        module2/
            [...]
        main.cpp
    test/
        test1.cpp
    resources/
        file.png
    bin
        [execute cmake ..]

그건 그렇고, 내 프로그램이 리소스가 어디에 있는지 아는 것이 중요합니다. 권장되는 리소스 관리 방법을 알고 싶습니다. “../resources/file.png”로 내 리소스에 액세스하고 싶지 않습니다.



답변

몇 가지 연구 끝에 이제는 가장 간단하지만 완전한 cmake 예제의 자체 버전을 얻었습니다. 여기에 있으며 리소스 및 패키지를 포함한 대부분의 기본 사항을 다루려고합니다.

비표준을 수행하는 한 가지는 리소스 처리입니다. 기본적으로 cmake는 이들을 / usr / share /, / usr / local / share / 및 Windows에서 이와 동등한 위치에 저장하려고합니다. 어디서나 압축을 풀고 실행할 수있는 간단한 zip / tar.gz를 갖고 싶었습니다. 따라서 리소스는 실행 파일에 상대적으로로드됩니다.

cmake 명령을 이해하기위한 기본 규칙은 <function-name>(<arg1> [<arg2> ...])쉼표 또는 반색없이 다음 구문
입니다. 각 인수는 문자열입니다. foobar(3.0)그리고 foobar("3.0")동일합니다. 을 사용하여 목록 / 변수를 설정할 수 있습니다 set(args arg1 arg2). 이 변수 세트로foobar(${args})foobar(arg1 arg2)효과적으로 동일하다. 존재하지 않는 변수는 빈 목록과 동일합니다. 목록은 내부적으로 요소를 구분하는 세미콜론이있는 문자열입니다. 따라서 하나의 요소 만 포함 된 목록은 정의에 따라 해당 요소 일 뿐이며 권투는 발생하지 않습니다. 변수는 전역 적입니다. 내장 함수는 또는 같은 ID를 기대한다는 사실에 의해 명명 된 인수의 형태를 제공합니다.PUBLICDESTINATION인수 목록에서 인수를 그룹화합니다. 그러나 그것은 언어 기능이 아니며, 이러한 ID는 문자열 일 뿐이며 함수 구현에 의해 구문 분석됩니다.

github 에서 모든 것을 복제 할 수 있습니다.

cmake_minimum_required(VERSION 3.0)
project(example_project)

###############################################################################
## file globbing ##############################################################
###############################################################################

# these instructions search the directory tree when cmake is
# invoked and put all files that match the pattern in the variables 
# `sources` and `data`
file(GLOB_RECURSE sources      src/main/*.cpp src/main/*.h)
file(GLOB_RECURSE sources_test src/test/*.cpp)
file(GLOB_RECURSE data resources/*)
# you can use set(sources src/main.cpp) etc if you don't want to
# use globing to find files automatically

###############################################################################
## target definitions #########################################################
###############################################################################

# add the data to the target, so it becomes visible in some IDE
add_executable(example ${sources} ${data})

# just for example add some compiler flags
target_compile_options(example PUBLIC -std=c++1y -Wall -Wfloat-conversion)

# this lets me include files relative to the root src dir with a <> pair
target_include_directories(example PUBLIC src/main)

# this copies all resource files in the build directory
# we need this, because we want to work with paths relative to the executable
file(COPY ${data} DESTINATION resources)

###############################################################################
## dependencies ###############################################################
###############################################################################

# this defines the variables Boost_LIBRARIES that contain all library names
# that we need to link to
find_package(Boost 1.36.0 COMPONENTS filesystem system REQUIRED)

target_link_libraries(example PUBLIC
  ${Boost_LIBRARIES}
  # here you can add any library dependencies
)

###############################################################################
## testing ####################################################################
###############################################################################

# this is for our testing framework
# we don't add REQUIRED because it's just for testing
find_package(GTest)

if(GTEST_FOUND)
  add_executable(unit_tests ${sources_test} ${sources})

  # we add this define to prevent collision with the main
  # this might be better solved by not adding the source with the main to the
  # testing target
  target_compile_definitions(unit_tests PUBLIC UNIT_TESTS)

  # this allows us to use our executable as a link library
  # therefore we can inherit all compiler options and library dependencies
  set_target_properties(example PROPERTIES ENABLE_EXPORTS on)

  target_link_libraries(unit_tests PUBLIC
    ${GTEST_BOTH_LIBRARIES}
    example
  )

  target_include_directories(unit_tests PUBLIC
    ${GTEST_INCLUDE_DIRS} # doesn't do anything on Linux
  )
endif()

###############################################################################
## packaging ##################################################################
###############################################################################

# all install commands get the same destination. this allows us to use paths
# relative to the executable.
install(TARGETS example DESTINATION example_destination)
# this is basically a repeat of the file copy instruction that copies the
# resources in the build directory, but here we tell cmake that we want it
# in the package
install(DIRECTORY resources DESTINATION example_destination)

# now comes everything we need, to create a package
# there are a lot more variables you can set, and some
# you need to set for some package types, but we want to
# be minimal here
set(CPACK_PACKAGE_NAME "MyExample")
set(CPACK_PACKAGE_VERSION "1.0.0")

# we don't want to split our program up into several things
set(CPACK_MONOLITHIC_INSTALL 1)

# This must be last
include(CPack)


답변

가장 기본적이지만 완전한 예제는 CMake 튜토리얼 에서 찾을 수 있습니다 .

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial tutorial.cxx)

프로젝트 예의 경우 다음이있을 수 있습니다.

cmake_minimum_required (VERSION 2.6)
project (MyProject)
add_executable(myexec src/module1/module1.cpp src/module2/module2.cpp src/main.cpp)
add_executable(mytest test1.cpp)

추가 질문에 대한 한 가지 방법은 자습서에서 다시 : 코드에 포함 할 구성 가능한 헤더 파일을 만드는 것입니다. 이를 위해 configuration.h.in다음 내용 으로 파일 을 만드십시오 .

#define RESOURCES_PATH "@RESOURCES_PATH@"

그런 다음 CMakeLists.txt추가 :

set(RESOURCES_PATH "${PROJECT_SOURCE_DIR}/resources/"
# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
  "${PROJECT_SOURCE_DIR}/configuration.h.in"
  "${PROJECT_BINARY_DIR}/configuration.h"
)

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")

마지막으로 코드에서 경로가 필요한 곳에서 다음을 수행 할 수 있습니다.

#include "configuration.h"

...

string resourcePath = string(RESOURCE_PATH) + "file.png";


답변

여기서는 가장 간단하지만 완전한 CMakeLists.txt 파일 샘플을 작성합니다.

소스 코드

  1. Hello World에서 크로스 플랫폼 Android / iOS / Web / Desktop에 이르는 튜토리얼.
  2. 각 플랫폼은 샘플 애플리케이션을 출시했습니다.
  3. 08-cross_platform 파일 구조체는 내 작업에 의해 확인됩니다.
  4. 완벽하지는 않지만 나 혼자 팀을위한 유용하고 모범 사례

그 후 세부 사항에 대한 문서를 제공했습니다.

질문이 있으시면 저에게 연락해 주시면 설명하겠습니다.


답변