CMake: Cấu trúc dự án với các bài kiểm tra đơn vị


139

Tôi đang cố gắng cấu trúc dự án của mình để bao gồm các nguồn sản xuất (trong srcthư mục con) và các thử nghiệm (trong testthư mục con). Tôi đang sử dụng CMake để xây dựng cái này. Như một ví dụ tối thiểu tôi có các tệp sau:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8) 
project (TEST) 

add_subdirectory (src) 
add_subdirectory (test) 

src / CMakeLists.txt:

add_executable (demo main.cpp sqr.cpp) 

src / sqr.h

#ifndef SQR_H
#define SQR_H
double sqr(double);    
#endif // SQR_H

src / sqr.cpp

#include "sqr.h"
double sqr(double x) { return x*x; }

src / main.cpp - sử dụng sqr, không thực sự quan trọng

kiểm tra / CMakeLists.txt:

find_package(Boost COMPONENTS system filesystem unit_test_framework REQUIRED)

include_directories (${TEST_SOURCE_DIR}/src) 

ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK) 

add_executable (test test.cpp ${TEST_SOURCE_DIR}/src/sqr.cpp) 

target_link_libraries(test
                      ${Boost_FILESYSTEM_LIBRARY}
                      ${Boost_SYSTEM_LIBRARY}
                      ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                      )

enable_testing()
add_test(MyTest test)

kiểm tra / test.cpp:

#define BOOST_TEST_MODULE SqrTests
#include <boost/test/unit_test.hpp>

#include "sqr.h"

BOOST_AUTO_TEST_CASE(FailTest)
{
    BOOST_CHECK_EQUAL(5, sqr(2));
}

BOOST_AUTO_TEST_CASE(PassTest)
{
    BOOST_CHECK_EQUAL(4, sqr(2));
}

Một số câu hỏi:

  1. Liệu cấu trúc này có ý nghĩa? Các thực hành tốt nhất khi cấu trúc mã này là gì? (Tôi đến từ C # và java, và ở đó dễ hiểu hơn)
  2. Tôi không thích thực tế là tôi phải liệt kê tất cả các tệp từ srcthư mục trong test/CMakeLists.txttệp. Nếu đây là một dự án thư viện, tôi sẽ chỉ liên kết thư viện. Có cách nào để tránh liệt kê tất cả các tệp cpp từ dự án khác không?
  3. Các dòng enable_testing()add_test(MyTest test)làm gì? Tôi chưa thấy hiệu quả. Làm cách nào tôi có thể chạy thử nghiệm từ CMake (hoặc CTest)?
  4. Cho đến nay tôi chỉ chạy cmake .trong thư mục gốc, nhưng điều này tạo ra một mớ hỗn độn với các tệp tạm thời ở khắp mọi nơi. Làm thế nào tôi có thể nhận được kết quả biên dịch trong một cấu trúc hợp lý?

Tôi tự coi mình là người mới làm CMake, vì vậy tôi không biết thực tiễn tốt nhất được chấp nhận là gì, nhưng FWIW tôi sẽ tạo một thư viện "sqr" * mà cả chính và thử nghiệm đều phụ thuộc vào. (* hoặc tương đương với đạo đức của chúng)
user786653

Câu trả lời:


125

Đối với câu hỏi 1 & 2, tôi khuyên bạn nên tạo một thư viện từ các tệp không kiểm tra của bạn ngoại trừ main.cpp (trong trường hợp này chỉ là src / sqr.cpp và src / sqr.h), và sau đó bạn có thể tránh liệt kê (và quan trọng hơn biên dịch lại) tất cả các nguồn hai lần.

Đối với câu hỏi 3, các lệnh này thêm một bài kiểm tra gọi là "MyTest" để gọi "kiểm tra" thực thi của bạn mà không có bất kỳ đối số nào. Tuy nhiên, vì bạn đã thêm các lệnh này vào test / CMakeLists.txt chứ không phải CMakeLists.txt cấp cao nhất của bạn, bạn chỉ có thể gọi thử nghiệm từ trong thư mục con "test" của cây xây dựng của mình (thử cd test && ctest -N). Nếu bạn muốn kiểm tra có thể chạy được từ thư mục xây dựng cấp cao nhất của mình, bạn cần gọi add_testtừ CMakeLists.txt cấp cao nhất. Điều này cũng có nghĩa là bạn phải sử dụng hình thức dài dòng hơn add_testvì exe thử nghiệm của bạn không được xác định trong cùng một CMakeLists.txt

Trong trường hợp của bạn, vì bạn đang chạy cmake trong thư mục gốc, cây xây dựng và cây nguồn của bạn là một và giống nhau. Đây được gọi là bản dựng trong nguồn và không lý tưởng, dẫn đến câu hỏi 4.

Phương thức ưa thích để tạo cây xây dựng là thực hiện xây dựng ngoài nguồn, tức là tạo một thư mục ở đâu đó bên ngoài cây nguồn của bạn và thực hiện cmake từ đó. Ngay cả việc tạo một thư mục "xây dựng" trong thư mục gốc của dự án và thực thi cmake ..sẽ cung cấp một cấu trúc sạch sẽ không can thiệp vào cây nguồn của bạn.

Một điểm cuối cùng là tránh gọi "test" (phân biệt chữ hoa chữ thường). Vì lý do tại sao, xem câu trả lời này .

Để đạt được những thay đổi này, tôi sẽ làm như sau:

CMakeLists.txt:

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src) 
add_subdirectory (test)
enable_testing ()
add_test (NAME MyTest COMMAND Test)


src / CMakeLists.txt:

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)


kiểm tra / CMakeLists.txt:

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )

2
Tôi chỉ nhận thấy rằng bạn cũng đã thêm các tệp .h vào các tệp CMakeLists.txt tương ứng. Có cần thiết không? Và chuyện gì sẽ xảy ra nếu tôi bỏ chúng?
Grzenio

3
@Grzenio Đây chỉ là một tính năng tiện lợi - chúng xuất hiện trong IDE giống như MSVC như một phần của mục tiêu, nhưng nếu không thì điều này không có tác dụng.
Fraser

1
TEST_SOURCE_DIR được đặt ở đâu?
agssol

6
Nó tự động được đặt bởi CMake khi gọi project (TEST)- xem cmake.org/cmake/help/v3.6/variable/PRO DỰ ÁN -NAME_SOURCE_DIR.html
Fraser

> chúng xuất hiện trong IDE giống như MSVC như một phần của mục tiêu --- MSVC không hỗ trợ đánh dấu thư mục bằng các tiêu đề là "thư mục bao gồm"?
isnullxbh

46

Tôi thích ví dụ về @Fraser nhưng sẽ sử dụng lệnh add_test trong test / CMakeLists.txt và sử dụng enable_testing trước khi add_subdirectory (test).

Bằng cách này, bạn có thể chạy thử nghiệm từ thư mục xây dựng cấp cao nhất trong khi chỉ định thử nghiệm của mình trong thử nghiệm / CMakeLists.txt.

Kết quả sẽ như thế này (tôi đã sử dụng lại ví dụ về @Fraser):

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project (TEST)
add_subdirectory (src)

enable_testing ()
add_subdirectory (test)

src / CMakeLists.txt

add_library (Sqr sqr.cpp sqr.h)
add_executable (demo main.cpp)
target_link_libraries (demo Sqr)

kiểm tra / CMakeLists.txt

find_package (Boost COMPONENTS system filesystem unit_test_framework REQUIRED)
include_directories (${TEST_SOURCE_DIR}/src
                     ${Boost_INCLUDE_DIRS}
                     )
add_definitions (-DBOOST_TEST_DYN_LINK)
add_executable (Test test.cpp)
target_link_libraries (Test
                       Sqr
                       ${Boost_FILESYSTEM_LIBRARY}
                       ${Boost_SYSTEM_LIBRARY}
                       ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
                       )
add_test (NAME MyTest COMMAND Test)

1
Cảm ơn, tôi đã cho thấy không có thử nghiệm nào ctest -Ncho đến khi bạn biết về việc bật thử nghiệm trước khi thêm thư mục con.
alaferg

@alaferg: nếu không họ sẽ kết thúc trong thư mục con thử nghiệm bên trong thư mục xây dựng.
gauteh

4
Tôi ước CMake có một cái gì đó giống cấu trúc.
ruipacheco
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.