C ++ 프로젝트 구성 (gtest, cmake 및 doxygen 사용)
나는 일반적으로 프로그래밍에 익숙하지 않기 때문에 C ++로 간단한 벡터 클래스를 만드는 것으로 시작하기로 결정했습니다. 그러나 나중에 워크 플로를 수정하지 않고 처음부터 좋은 습관을 갖고 싶습니다.
저는 현재 두 파일을 가지고 vector3.hpp
와 vector3.cpp
. 이 프로젝트는 모든 것에 익숙해 짐에 따라 서서히 성장하기 시작합니다 (일반 선형 대수 라이브러리보다 훨씬 더 많이 만들어 짐). 따라서 나중에보다 쉽게 사용할 수 있도록 "표준"프로젝트 레이아웃을 채택하고 싶습니다. 그래서 둘러 본 후 hpp 및 cpp 파일을 구성하는 두 가지 방법을 찾았습니다.
project
└── src
├── vector3.hpp
└── vector3.cpp
두 번째는 :
project
├── inc
│ └── project
│ └── vector3.hpp
└── src
└── vector3.cpp
어느 것을 추천하고 왜 하시겠습니까?
둘째, 코드를 사용하기 매우 쉬운 것처럼 단위 테스트를 위해 Google C ++ Testing Framework를 사용하고 싶습니다. 이 코드를 예를 들어 inc/gtest
또는 contrib/gtest
폴더 에 내 코드와 함께 제공하는 것이 좋습니다 . 번들로 제공되는 경우 fuse_gtest_files.py
스크립트를 사용하여 수 또는 파일을 줄이거 나 그대로 두는 것이 좋습니다 . 번들로 제공되지 않으면이 종속성은 어떻게 처리됩니까?
작문 시험과 관련하여 일반적으로 이러한 시험은 어떻게 구성됩니까? 나는 각 클래스마다 하나의 cpp 파일을 가지고 있다고 생각 test_vector3.cpp
했지만 ( 예 :) 모두 하나의 바이너리로 컴파일되어 모두 쉽게 실행될 수 있습니까?
gtest 라이브러리는 일반적으로 cmake 및 make를 사용하여 빌드되므로 프로젝트도 이와 같이 빌드하는 것이 합리적이라고 생각했습니다. 다음 프로젝트 레이아웃을 사용하기로 결정한 경우 :
├── CMakeLists.txt
├── contrib
│ └── gtest
│ ├── gtest-all.cc
│ └── gtest.h
├── docs
│ └── Doxyfile
├── inc
│ └── project
│ └── vector3.cpp
├── src
│ └── vector3.cpp
└── test
└── test_vector3.cpp
어떻게는 것 CMakeLists.txt
이 중 단지 라이브러리 또는 라이브러리와 테스트를 구축 할 수 있도록보고있다? 또한 나는이 꽤 몇 가지 프로젝트 본 build
과 bin
디렉토리를. 빌드 디렉토리에서 빌드가 발생하고 바이너리가 bin 디렉토리로 이동 되었습니까? 테스트 바이너리와 라이브러리가 같은 장소에 있습니까? 또는 다음과 같이 구성하는 것이 더 합리적입니다.
test
├── bin
├── build
└── src
└── test_vector3.cpp
또한 doxygen을 사용하여 코드를 문서화하고 싶습니다. cmake 및 make로 자동 실행되도록 할 수 있습니까?
많은 질문에 대해 죄송하지만 C ++에 대한 이러한 질문에 대한 대답을 찾을 수있는 책을 찾지 못했습니다.
C ++ 빌드 시스템은 약간의 검은 예술이며 프로젝트가 오래 될수록 더 이상한 것을 찾을 수 있으므로 많은 질문이 제기되는 것은 놀라운 일이 아닙니다. 질문을 하나씩 살펴보고 C ++ 라이브러리 빌드와 관련된 일반적인 사항을 언급하려고합니다.
디렉토리에서 헤더 및 cpp 파일 분리 실제 응용 프로그램이 아닌 라이브러리로 사용되는 구성 요소를 작성하는 경우에만 필수입니다. 헤더는 사용자가 제공하는 것과 상호 작용하고 설치해야하는 기초입니다. 즉, 하위 디렉토리에 있어야하고 (아무도 최상위 헤더로 끝나는 /usr/include/
헤더가 많지 않아야 함) 헤더에 이러한 설정을 포함 할 수 있어야합니다.
└── prj
├── include
│ └── prj
│ ├── header2.h
│ └── header.h
└── src
└── x.cpp
포함 경로가 제대로 작동하므로 설치 대상을 쉽게 붙일 수 있습니다.
의존성 번들링 : 이것은 의존성이 찾고 빌드하는 빌드 시스템의 능력과 단일 버전에 대한 코드의 의존성에 달려 있다고 생각합니다. 또한 사용자의 능력과 플랫폼에 종속성을 설치하는 것이 얼마나 쉬운 지에 따라 다릅니다. CMake는 find_package
Google Test 용 스크립트 와 함께 제공됩니다 . 이것은 일을 훨씬 쉽게 만듭니다. 필요할 때만 번들링을하고 달리 피하십시오.
빌드 방법 : 소스 빌드를 피하십시오. CMake는 소스 빌드를 쉽게 만들고 삶을 훨씬 쉽게 만듭니다.
CTest를 사용하여 시스템 테스트를 실행하려고한다고 가정합니다 (GTest에 대한 내장 지원도 제공됨). 디렉토리 레이아웃 및 테스트 조직에 대한 중요한 결정은 다음과 같습니다. 하위 프로젝트로 끝납니 까? 그렇다면 CMakeLists를 설정할 때 더 많은 작업이 필요하며 하위 프로젝트를 각각 고유 한 파일 include
과 src
파일을 가진 하위 디렉토리로 분할해야 합니다. 어쩌면 그들 자신의 doxygen 실행 및 출력 (여러 doxygen 프로젝트를 결합하는 것은 가능하지만 쉽지 않거나 예쁘지 않습니다).
다음과 같은 결과가 나타납니다.
└── prj
├── CMakeLists.txt <-- (1)
├── include
│ └── prj
│ ├── header2.hpp
│ └── header.hpp
├── src
│ ├── CMakeLists.txt <-- (2)
│ └── x.cpp
└── test
├── CMakeLists.txt <-- (3)
├── data
│ └── testdata.yyy
└── testcase.cpp
어디
- (1) 종속성, 플랫폼 별 및 출력 경로를 구성합니다
- (2) 빌드 할 라이브러리를 구성합니다
- (3) 테스트 실행 파일 및 테스트 사례를 구성합니다
하위 구성 요소가있는 경우 다른 계층 구조를 추가하고 각 하위 프로젝트에 대해 위의 트리를 사용하는 것이 좋습니다. 하위 구성 요소가 종속 항목을 검색하고 구성하는지 또는 최상위 수준에서 구성하는지 결정해야하기 때문에 상황이 까다로워집니다. 이는 사례별로 결정해야합니다.
Doxygen : doxygen의 구성 댄스를 수행 한 후에는 CMake add_custom_command
를 사용 하여 문서 대상을 추가하는 것이 쉽지 않습니다.
이것은 내 프로젝트가 끝나는 방식이며 매우 유사한 프로젝트를 보았지만 물론 모든 치료법은 아닙니다.
부록 어떤 시점 config.hpp
에서 버전 정의와 일부 버전 제어 식별자 (Git 해시 또는 SVN 개정 번호)에 대한 정의를 포함 하는 파일 을 생성하려고 할 것 입니다. CMake에는 해당 정보 찾기를 자동화하고 파일을 생성하는 모듈이 있습니다. CMake를 사용 configure_file
하여 템플릿 파일의 변수를에 정의 된 변수로 바꿀 수 있습니다 CMakeLists.txt
.
라이브러리를 빌드하는 경우 __declspec
MSVC와 visibility
GCC / clang의 속성 과 같은 컴파일러 간의 차이를 얻기 위해 내보내기 정의도 필요합니다 .
우선, 무시할 수없는 디렉토리에 대한 일반적인 이름이 있는데, 이는 Unix 파일 시스템의 오랜 전통을 기반으로합니다. 이것들은:
trunk
├── bin : for all executables (applications)
├── lib : for all other binaries (static and shared libraries (.so or .dll))
├── include : for all header files
├── src : for source files
└── doc : for documentation
최소한 기본적으로이 기본 레이아웃을 고수하는 것이 좋습니다.
헤더 파일과 소스 파일 (cpp)을 분할하는 방법에 대해서는 두 가지 방식이 상당히 일반적입니다. 그러나 나는 그것들을 함께 유지하는 것을 선호합니다. 일상적인 작업에서 파일을 함께 사용하는 것이 더 실용적입니다. 또한 모든 코드가 하나의 최상위 폴더 (예 : 폴더) 아래에 있으면 최상위 레벨에 trunk/src/
있는 다른 모든 폴더 (bin, lib, include, doc 및 일부 테스트 폴더)가 추가로 표시됩니다. 소스 외부 빌드의 "build"디렉토리는 빌드 프로세스에서 생성 된 파일 만 포함하는 모든 폴더입니다. 따라서 src 폴더 만 백업하거나 버전 관리 시스템 / 서버 (Git 또는 SVN과 같은)에 보관하는 것이 훨씬 좋습니다.
그리고 대상 시스템에 헤더 파일을 설치하는 경우 (결국 라이브러리를 배포하려는 경우) CMake에는 파일을 설치하는 명령이 있습니다 (암시 적으로 "install"대상을 생성하고 "make install"을 수행함). 모든 헤더를 /usr/include/
디렉토리 에 넣는 데 사용할 수 있습니다 . 이 목적으로 다음 cmake 매크로를 사용합니다.
# custom macro to register some headers as target for installation:
# setup_headers("/path/to/header/something.h" "/relative/install/path")
macro(setup_headers HEADER_FILES HEADER_PATH)
foreach(CURRENT_HEADER_FILE ${HEADER_FILES})
install(FILES "${SRCROOT}${CURRENT_HEADER_FILE}" DESTINATION "${INCLUDEROOT}${HEADER_PATH}")
endforeach(CURRENT_HEADER_FILE)
endmacro(setup_headers)
어디 SRCROOT
내가 src 폴더로 설정하는 cmake 변수이며, INCLUDEROOT
내가 헤더에 갈 필요가 어디든지 구성하는 것이 cmake 변수입니다. 물론 이렇게하는 다른 방법이 많이 있으며, 제 방법이 최선이 아닌 것 같습니다. 요점은 대상 시스템에 헤더 만 설치하면되기 때문에 헤더와 소스를 분리 할 이유가 없습니다. 특히 CMake (또는 CPack)를 사용하여 헤더를 선택하고 구성하기가 매우 쉽기 때문입니다. 별도의 디렉토리에 설치하지 않아도 설치됩니다. 이것이 대부분의 도서관에서 본 것입니다.
인용 : 둘째, 코드를 사용하기 매우 쉬운 것처럼 단위 테스트를 위해 Google C ++ Testing Framework를 사용하고 싶습니다. 예를 들어 "inc / gtest"또는 "contrib / gtest"폴더와 같이이 코드를 내 코드와 함께 제공하는 것이 좋습니다. 번들로 제공되는 경우 fuse_gtest_files.py 스크립트를 사용하여 수를 줄이거 나 그대로 두는 것이 좋습니다. 번들로 제공되지 않으면이 종속성은 어떻게 처리됩니까?
라이브러리와 종속성을 묶지 마십시오. 이것은 일반적으로 꽤 끔찍한 아이디어이며, 그렇게하는 라이브러리를 만들려고 할 때 항상 싫어합니다. 최후의 수단이어야하며 함정에주의하십시오. 사람들은 종종 끔찍한 개발 환경 (예 : Windows)을 대상으로하거나 문제가있는 오래된 (더 이상 사용되지 않는) 버전의 라이브러리 (종속성) 만 지원하기 때문에 라이브러리와의 종속성을 번들로 묶습니다. 주요 함정은 번들 종속성이 이미 설치된 동일한 라이브러리 / 응용 프로그램 버전과 충돌 할 수 있다는 것입니다 (예 : gtest를 번들로 묶었지만 라이브러리를 빌드하려는 사람은 이미 최신 또는 이전 버전의 gtest를 설치 한 다음 두 사람이 충돌하여 그 사람에게 심한 두통을 줄 수 있습니다). 내가 말했듯이, 당신의 책임하에하세요 그리고 나는 최후의 수단으로 만 말할 것입니다. 라이브러리를 컴파일하기 전에 사람들에게 몇 가지 종속성을 설치하도록 요청하는 것은 번들 종속성과 기존 설치 간의 충돌을 해결하는 것보다 훨씬 덜 악합니다.
인용문 : 작문 시험과 관련하여 일반적으로 어떻게 구성됩니까? 각 클래스마다 하나의 cpp 파일 (예 : test_vector3.cpp)을 가지고 있지만 모두 하나의 바이너리로 컴파일되어 쉽게 함께 실행할 수 있습니까?
클래스 당 하나의 cpp 파일 (또는 작은 응집력있는 클래스 및 함수 그룹)은 제 생각에 더 일반적이며 실용적입니다. 그러나 "모두 함께 실행할 수 있도록"모두 하나의 바이너리로 컴파일하지 마십시오. 정말 나쁜 생각입니다. 일반적으로 코딩과 관련하여 합리적으로 분할하는 것이 좋습니다. 단위 테스트의 경우 하나의 바이너리가 모든 테스트를 실행하는 것을 원하지 않습니다. 즉, 라이브러리의 내용을 조금만 변경해도 해당 단위 테스트 프로그램을 거의 완전히 다시 컴파일 할 수 있기 때문입니다. 재 컴파일을 기다리는 데 몇 분 / 시간이 걸립니다. 간단한 계획을 고수하십시오 : 1 단위 = 1 단위 테스트 프로그램. 그때,
인용 : gtest 라이브러리는 일반적으로 cmake 및 make를 사용하여 빌드되므로 프로젝트도 이와 같이 빌드하는 것이 의미가 있다고 생각했습니다. 다음 프로젝트 레이아웃을 사용하기로 결정한 경우 :
차라리이 레이아웃을 제안하고 싶습니다.
trunk
├── bin
├── lib
│ └── project
│ └── libvector3.so
│ └── libvector3.a products of installation / building
├── docs
│ └── Doxyfile
├── include
│ └── project
│ └── vector3.hpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── src
│ └── CMakeLists.txt
│ └── Doxyfile.in
│ └── project part of version-control / source-distribution
│ └── CMakeLists.txt
│ └── vector3.hpp
│ └── vector3.cpp
│ └── test
│ └── test_vector3.cpp
│_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
│
├── build
└── test working directories for building / testing
└── test_vector3
여기에 몇 가지주의 할 사항이 있습니다. 첫째, src 디렉토리의 하위 디렉토리는 include 디렉토리의 하위 디렉토리를 미러링해야합니다. 이것은 직관적으로 유지하는 것입니다 (폴더의 깊은 중첩 때문에 하위 디렉토리 구조를 합리적으로 평평하게 유지하십시오 (얕은)). 종종 다른 것보다 번거 로움이 많습니다). 둘째, "include"디렉토리는 단지 설치 디렉토리이며 그 내용은 src 디렉토리에서 선택되는 헤더입니다.
셋째, CMake 시스템은 최상위 레벨에있는 하나의 CMakeLists.txt 파일이 아니라 소스 서브 디렉토리에 분산됩니다. 이것은 일을 지역적으로 유지하며 좋은 일입니다 (사물을 독립적 인 조각으로 나누는 정신에서). 새 소스, 새 헤더 또는 새 테스트 프로그램을 추가하는 경우 문제가되는 하위 디렉토리에서 작고 간단한 CMakeLists.txt 파일 하나만 편집하면됩니다. 또한 디렉토리를 쉽게 재구성 할 수 있습니다 (CMakeList는 로컬이며 이동중인 서브 디렉토리에 포함됨). 최상위 CMakeLists에는 대상 디렉토리 설정, 사용자 지정 명령 (또는 매크로) 및 시스템에 설치된 패키지 찾기와 같은 대부분의 최상위 구성이 포함되어야합니다. 하위 레벨 CMakeList에는 간단한 헤더, 소스 목록,
인용 : CMakeLists.txt는 라이브러리 나 라이브러리 및 테스트 만 빌드 할 수 있도록 어떻게보아야합니까?
기본 답변은 CMake를 사용하면 특정 대상을 "all"( "make"를 입력 할 때 빌드되는 대상)에서 구체적으로 제외 할 수 있으며 특정 대상 묶음을 만들 수도 있다는 것입니다. 여기서는 CMake 자습서를 수행 할 수 없지만 직접 알아내는 것이 매우 간단합니다. 그러나이 특정한 경우에 권장되는 솔루션은 물론 CMakeLists 파일에서 단위로 표시된 여러 대상 (프로그램)을 등록하기 위해 사용할 수있는 추가 명령 세트 인 CTest를 사용하는 것입니다. 테스트. 따라서 CMake는 모든 테스트를 특수한 범주의 빌드에 넣습니다. 이것이 바로 여러분이 요청한 문제입니다.
인용구 : 또한 빌드 디렉토리에 bin 디렉토리가있는 꽤 많은 프로젝트를 보았습니다. 빌드 디렉토리에서 빌드가 발생하고 바이너리가 bin 디렉토리로 이동 되었습니까? 테스트 바이너리와 라이브러리가 같은 장소에 있습니까? 또는 다음과 같이 구성하는 것이 더 합리적입니다.
소스 외부에 빌드 디렉토리 ( "out-of-source"빌드)를 갖는 것이 실제로해야 할 유일한 일입니다. 요즘은 사실상의 표준입니다. 따라서 CMake 사람들이 권장하는 것처럼, 내가 만난 모든 프로그래머가하는 것처럼 소스 디렉토리 외부에 별도의 "빌드"디렉토리가 있어야합니다. bin 디렉토리에 관해서는 이것이 관례이며,이 게시물의 시작 부분에서 언급했듯이 아마도 그것을 고수하는 것이 좋습니다.
견적 : 또한 코드를 문서화하기 위해 doxygen을 사용하고 싶습니다. cmake 및 make로 자동 실행되도록 할 수 있습니까?
예. 그것은 가능 이상이며, 굉장합니다. 얼마나 멋진 걸 원하느냐에 따라 몇 가지 가능성이 있습니다. CMake에는 Doxygen 용 모듈 (예 find_package(Doxygen)
:)이있어 일부 파일에서 Doxygen을 실행할 대상을 등록 할 수 있습니다. Doxyfile에서 버전 번호를 업데이트하거나 소스 파일에 날짜 / 작성자 스탬프를 자동으로 입력하는 등의 더 멋진 작업을 수행하려면 약간의 CMake kung-fu를 사용하면 가능합니다. 일반적으로이 작업을 수행하려면 CMake의 구문 분석 명령으로 토큰을 찾아서 교체 할 소스 Doxyfile (예 : 위의 폴더 레이아웃에 넣은 "Doxyfile.in")을 유지해야합니다. 에서 내 최상위 CMakeLists 파일 , 당신은 cmake-doxygen이의 함께 몇 가지 멋진 일을 CMake 쿵후의 하나 개의 조각을 찾을 수 있습니다.
프로젝트 구조화
나는 일반적으로 다음을 선호합니다.
├── CMakeLists.txt
|
├── docs/
│ └── Doxyfile
|
├── include/
│ └── project/
│ └── vector3.hpp
|
├── src/
└── project/
└── vector3.cpp
└── test/
└── test_vector3.cpp
즉, 라이브러리에 대해 매우 명확하게 정의 된 API 파일 세트가 있으며이 구조는 라이브러리의 클라이언트가 수행함을 의미합니다.
#include "project/vector3.hpp"
덜 명시 적이기보다는
#include "vector3.hpp"
/ src 트리의 구조가 / include 트리의 구조와 일치하지만 개인적으로 선호합니다. 그러나 프로젝트가 / include / project 내에 하위 디렉토리를 포함하도록 확장되면 일반적으로 / src 트리 내의 하위 디렉토리와 일치하는 데 도움이됩니다.
테스트를 위해 테스트 할 파일과 "가까운"상태를 유지하는 것이 좋으며, / src 내에 하위 디렉토리가있는 경우 다른 사람들이 특정 파일의 테스트 코드를 찾으려면 따라 가기 쉬운 패러다임입니다.
테스팅
둘째, 코드를 사용하기 매우 쉬운 것처럼 단위 테스트를 위해 Google C ++ Testing Framework를 사용하고 싶습니다.
Gtest는 실제로 사용하기 간단하고 기능면에서 상당히 포괄적입니다. gmock 과 함께 기능을 확장하기 위해 매우 쉽게 사용할 수 있지만 gmock에 대한 내 경험은 덜 호의적입니다. 나는 이것이 내 자신의 단점으로 이어질 수 있다는 것을 받아 들일 준비가되어 있지만 모의 테스트는 만들기가 더 어려워지고 유지하기가 훨씬 더 어려워지는 경향이 있습니다. gmock 관의 큰 못은 실제로 똑똑한 포인터로 잘 어울리지 않는다는 것입니다.
이것은 거대한 질문에 대한 매우 사소하고 주관적인 답변입니다 (아마도 SO에 속하지는 않습니다)
예를 들어 "inc / gtest"또는 "contrib / gtest"폴더와 같이이 코드를 내 코드와 함께 제공하는 것이 좋습니다. 번들로 제공되는 경우 fuse_gtest_files.py 스크립트를 사용하여 수를 줄이거 나 그대로 두는 것이 좋습니다. 번들로 제공되지 않으면이 종속성은 어떻게 처리됩니까?
CMake ExternalProject_Add
모듈을 선호 합니다. 이를 통해 저장소에 gtest 소스 코드를 유지하거나 어디서나 설치할 수 있습니다. 빌드 트리에서 자동으로 다운로드되어 빌드됩니다.
작문 시험과 관련하여 일반적으로 이러한 시험은 어떻게 구성됩니까? 각 클래스마다 하나의 cpp 파일 (예 : test_vector3.cpp)을 가지고 있지만 모두 하나의 바이너리로 컴파일되어 쉽게 함께 실행할 수 있습니까?
좋은 계획.
건물
저는 CMake의 팬이지만 테스트 관련 질문과 마찬가지로 주관적인 문제에 대한 의견을 요청하기에 가장 좋은 장소는 아닙니다.
CMakeLists.txt는 라이브러리 나 라이브러리 및 테스트 만 빌드 할 수 있도록 어떻게보아야합니까?
add_library(ProjectLibrary <All library sources and headers>)
add_executable(ProjectTest <All test files>)
target_link_libraries(ProjectTest ProjectLibrary)
라이브러리는 대상 "ProjectLibrary"로, 테스트 스위트는 대상 "ProjectTest"로 나타납니다. 라이브러리를 테스트 exe의 종속성으로 지정하면 테스트 exe를 빌드하면 라이브러리가 오래되면 자동으로 다시 빌드됩니다.
또한 빌드 광고에 bin 디렉토리가있는 꽤 많은 프로젝트를 보았습니다. 빌드 디렉토리에서 빌드가 발생하고 바이너리가 bin 디렉토리로 이동 되었습니까? 테스트 바이너리와 라이브러리가 같은 장소에 있습니까?
CMake는 "소스 외부"빌드를 권장합니다. 즉, 프로젝트 외부에 자체 빌드 디렉토리를 작성하고 거기서 CMake를 실행합니다. 이렇게하면 빌드 파일로 소스 트리를 "오염"시키지 않으며 vc를 사용하는 경우 매우 바람직합니다.
당신은 할 수 있습니다 내장되면 바이너리를 이동하거나 다른 디렉토리에 복사하도록 지정하거나 다른 디렉토리에 기본적으로 생성됩니다,하지만 필요는 일반적으로 없다. CMake는 원하는 경우 프로젝트를 설치하는 포괄적 인 방법을 제공하거나 다른 CMake 프로젝트가 프로젝트의 관련 파일을 쉽게 찾을 수 있도록합니다.
gtest 테스트 찾기 및 실행에 대한 CMake의 자체 지원 과 관련 하여 프로젝트의 일부로 gtest를 빌드하는 경우 이는 부적절합니다. 이 FindGtest
모듈은 실제로 프로젝트 외부에서 gtest가 별도로 구축 된 경우에 사용되도록 설계되었습니다.
CMake는 자체 테스트 프레임 워크 (CTest)를 제공하며 이상적으로 모든 gtest 케이스는 CTest 케이스로 추가됩니다.
그러나 개별 ctest 사례로 gtest 사례를 쉽게 추가 할 수 있도록 GTEST_ADD_TESTS
제공된 FindGtest
매크로는 TEST
및 이외의 gtest 매크로에는 작동하지 않는다는 점에서 다소 부족 TEST_F
합니다. 부가가치 또는 타입 매개 변수화 시험 사용 TEST_P
, TYPED_TEST_P
등 전혀 처리되지 않습니다.
문제는 내가 아는 쉬운 해결책이 없습니다. gtest 사례 목록을 얻는 가장 강력한 방법은 플래그를 사용하여 test exe를 실행하는 것 --gtest_list_tests
입니다. 그러나 이것은 exe가 빌드 된 후에 만 수행 할 수 있으므로 CMake는이를 사용할 수 없습니다. 두 가지 선택을 할 수 있습니다. CMake는 테스트 이름을 추론하기 위해 C ++ 코드를 구문 분석하려고 시도해야합니다 (모든 gtest 매크로, 주석 처리 된 테스트, 비활성화 된 테스트를 고려하려는 경우 극단적으로 쉽지는 않습니다). CMakeLists.txt 파일.
또한 doxygen을 사용하여 코드를 문서화하고 싶습니다. cmake 및 make로 자동 실행되도록 할 수 있습니까?
예-비록이 분야에 대한 경험이 없지만. CMake는 FindDoxygen
이 목적을 제공합니다 .
다른 (우수한) 답변 외에도 상대적 으로 대규모 프로젝트 에 사용한 구조를 설명하겠습니다 .
나는 다른 답변에서 언급 된 것을 반복하기 때문에 Doxygen에 대한 하위 질문을 다루지 않을 것입니다.
이론적 해석
모듈 성과 유지 보수성을 위해 프로젝트는 작은 단위로 구성됩니다. 명확하게하기 위해 X = A, B, C, ...를 사용하여 UnitX라는 이름을 지정합니다 (그러나 일반적인 이름을 가질 수 있음). 그런 다음 디렉토리 구조는이 선택을 반영하여 구성되며 필요한 경우 장치를 그룹화 할 수 있습니다.
해결책
기본 디렉토리 레이아웃은 다음과 같습니다 (단위 내용은 나중에 자세히 설명합니다).
project
├── CMakeLists.txt
├── UnitA
├── UnitB
├── GroupA
│ └── CMakeLists.txt
│ └── GroupB
│ └── CMakeLists.txt
│ └── UnitC
│ └── UnitD
│ └── UnitE
project/CMakeLists.txt
다음을 포함 할 수 있습니다.
cmake_minimum_required(VERSION 3.0.2)
project(project)
enable_testing() # This will be necessary for testing (details below)
add_subdirectory(UnitA)
add_subdirectory(UnitB)
add_subdirectory(GroupA)
그리고 project/GroupA/CMakeLists.txt
:
add_subdirectory(GroupB)
add_subdirectory(UnitE)
그리고 project/GroupB/CMakeLists.txt
:
add_subdirectory(UnitC)
add_subdirectory(UnitD)
이제 다른 단위의 구조로 (UnitD를 예로 들어 보자)
project/GroupA/GroupB/UnitD
├── README.md
├── CMakeLists.txt
├── lib
│ └── CMakeLists.txt
│ └── UnitD
│ └── ClassA.h
│ └── ClassA.cpp
│ └── ClassB.h
│ └── ClassB.cpp
├── test
│ └── CMakeLists.txt
│ └── ClassATest.cpp
│ └── ClassBTest.cpp
│ └── [main.cpp]
To the different components:
- I like having source (
.cpp
) and headers (.h
) in the same folder. This avoids a duplicate directory hierarchy, makes maintenance easier. For installation, it is no problem (especially with CMake) to just filter the header files. - The role of the directory
UnitD
is to later on allow including files with#include <UnitD/ClassA.h>
. Also, when installing this unit, you can just copy the directory structure as is. Note that you can also organize your source files in subdirectories. - I like a
README
file to summarize what the unit is about and specify useful information about it. CMakeLists.txt
could simply contain:add_subdirectory(lib) add_subdirectory(test)
lib/CMakeLists.txt
:project(UnitD) set(headers UnitD/ClassA.h UnitD/ClassB.h ) set(sources UnitD/ClassA.cpp UnitD/ClassB.cpp ) add_library(${TARGET_NAME} STATIC ${headers} ${sources}) # INSTALL_INTERFACE: folder to which you will install a directory UnitD containing the headers target_include_directories(UnitD PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> PUBLIC $<INSTALL_INTERFACE:include/SomeDir> ) target_link_libraries(UnitD PUBLIC UnitA PRIVATE UnitC )
Here, note that it is not necessary to tell CMake that we want the include directories for
UnitA
andUnitC
, as this was already specified when configuring those units. Also,PUBLIC
will tell all targets that depend onUnitD
that they should automatically include theUnitA
dependency, whileUnitC
won't be required then (PRIVATE
).test/CMakeLists.txt
(see further below if you want to use GTest for it):project(UnitDTests) add_executable(UnitDTests ClassATest.cpp ClassBTest.cpp [main.cpp] ) target_link_libraries(UnitDTests PUBLIC UnitD ) add_test( NAME UnitDTests COMMAND UnitDTests )
Using GoogleTest
For Google Test, the easiest is if its source is present in somewhere your source directory, but you don't have to actually add it there yourself. I've been using this project to download it automatically, and I wrap its usage in a function to make sure that it is downloaded only once, even though we have several test targets.
This CMake function is the following:
function(import_gtest)
include (DownloadProject)
if (NOT TARGET gmock_main)
include(DownloadProject)
download_project(PROJ googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.8.0
UPDATE_DISCONNECTED 1
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Prevent GoogleTest from overriding our compiler/linker options when building with Visual Studio
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
endfunction()
and then, when I want to use it inside one of my test targets, I will add the following lines to the CMakeLists.txt
(this is for the example above, test/CMakeLists.txt
):
import_gtest()
target_link_libraries(UnitDTests gtest_main gmock_main)
참고URL : https://stackoverflow.com/questions/13521618/c-project-organisation-with-gtest-cmake-and-doxygen
'IT story' 카테고리의 다른 글
subscribe 결과는 사용되지 않습니다 (0) | 2020.07.26 |
---|---|
부울에 대해 C ++에 && = 또는 || =가없는 이유는 무엇입니까? (0) | 2020.07.26 |
더 효율적인 것은 무엇입니까? (0) | 2020.07.26 |
실행 일시 중지, 잠자기, R에서 X 초 동안 기다리는 방법은 무엇입니까? (0) | 2020.07.26 |
pip freeze 명령 출력에서“pkg-resources == 0.0.0”이란 무엇입니까 (0) | 2020.07.26 |