CMake: โครงสร้างโครงการพร้อมการทดสอบหน่วย


139

ฉันกำลังพยายามจัดโครงสร้างโครงการของฉันเพื่อรวมแหล่งผลิต (ในsrcโฟลเดอร์ย่อย) และการทดสอบ (ในtestโฟลเดอร์ย่อย) ฉันใช้ CMake เพื่อสร้างสิ่งนี้ ตัวอย่างเล็ก ๆ น้อย ๆ ฉันมีไฟล์ต่อไปนี้:

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 - ใช้ sqr ไม่สำคัญจริงๆ

การทดสอบ / 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)

การทดสอบ / 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));
}

คำถามเล็กน้อย:

  1. โครงสร้างนี้เหมาะสมหรือไม่ แนวทางปฏิบัติที่ดีที่สุดคืออะไรเมื่อสร้างรหัสนี้ (ฉันมาจาก C # และ java และมีความรู้สึกง่ายกว่า)
  2. ฉันไม่ชอบความจริงที่ว่าฉันต้องแสดงรายการไฟล์ทั้งหมดจากsrcโฟลเดอร์ในtest/CMakeLists.txtไฟล์ หากนี่เป็นโครงการห้องสมุดฉันจะลิงก์ห้องสมุด มีวิธีหลีกเลี่ยงการแสดงรายการไฟล์ cpp ทั้งหมดจากโครงการอื่นหรือไม่?
  3. สิ่งที่เป็นเส้นenable_testing()และadd_test(MyTest test)ทำอะไร ฉันไม่เห็นผลใด ๆ ฉันจะทำการทดสอบจาก CMake (หรือ CTest) ได้อย่างไร
  4. จนถึงตอนนี้ฉันเพิ่งรันcmake .ในโฟลเดอร์ราก แต่สิ่งนี้สร้างความยุ่งเหยิงด้วยไฟล์ชั่วคราวทุกที่ ฉันจะรับผลลัพธ์การรวบรวมในโครงสร้างที่เหมาะสมได้อย่างไร

ฉันพิจารณาตัวเองว่าเป็นมือใหม่ของ CMake ดังนั้นฉันจึงไม่รู้ว่าแนวทางปฏิบัติที่ดีที่สุดที่ยอมรับคืออะไร แต่ FWIW ฉันจะสร้างห้องสมุด "sqr" * ที่ทั้งการทดสอบหลักและการทดสอบนั้นขึ้นอยู่กับ (* หรือเทียบเท่าทางศีลธรรมของมัน)
user786653

คำตอบ:


125

สำหรับคำถามที่ 1 & 2 ฉันขอแนะนำให้สร้างห้องสมุดจากไฟล์ที่ไม่ใช่การทดสอบของคุณยกเว้น main.cpp (ในกรณีนี้แค่ src / sqr.cpp และ src / sqr.h) จากนั้นคุณสามารถหลีกเลี่ยงรายการ (และที่สำคัญกว่านั้น) รวบรวมใหม่) แหล่งที่มาทั้งหมดสองครั้ง

สำหรับคำถามที่ 3 คำสั่งเหล่านี้จะเพิ่มการทดสอบที่เรียกว่า "MyTest" ซึ่งเรียกใช้ "การทดสอบ" ที่ปฏิบัติการได้ของคุณโดยไม่มีข้อโต้แย้งใด ๆ อย่างไรก็ตามเนื่องจากคุณได้เพิ่มคำสั่งเหล่านี้เพื่อทดสอบ / CMakeLists.txt และไม่ใช่ CMakeLists.txt ระดับบนสุดของคุณคุณสามารถเรียกใช้การทดสอบได้จากภายในไดเรกทอรีย่อย "ทดสอบ" ของโครงสร้างการสร้างของคุณ (ลองcd test && ctest -N) หากคุณต้องการให้การทดสอบรันได้จากไดเรกทอรีadd_testบิลด์ระดับบนสุดคุณจะต้องโทรจาก CMakeLists.txt ระดับบนสุด นอกจากนี้ยังหมายความว่าคุณต้องใช้รูปแบบ verbose มากขึ้นadd_testเนื่องจาก exe ทดสอบของคุณไม่ได้ถูกกำหนดใน CMakeLists.txt เดียวกัน

ในกรณีของคุณเนื่องจากคุณกำลังเรียกใช้ cmake ในโฟลเดอร์รากทรีบิลด์ของคุณและทรีซอร์สของคุณจะเหมือนกัน สิ่งนี้เรียกว่าการสร้างในแหล่งและไม่เหมาะซึ่งนำไปสู่คำถามที่ 4

วิธีที่ต้องการสำหรับการสร้างโครงสร้างการสร้างคือการสร้างนอกแหล่งที่มาเช่นสร้างไดเรกทอรีที่ไหนสักแห่งนอกต้นไม้ต้นกำเนิดของคุณและดำเนินการ cmake จากที่นั่น แม้แต่การสร้างไดเรกทอรี "สร้าง" ในรากของโครงการของคุณและการดำเนินการcmake ..จะให้โครงสร้างที่สะอาดซึ่งจะไม่รบกวนต้นไม้ต้นกำเนิดของคุณ

จุดสุดท้ายที่หนึ่งคือการหลีกเลี่ยงการเรียกใช้ "การทดสอบ" (แบบตรงตามตัวพิมพ์ใหญ่ - เล็ก) สำหรับสาเหตุที่เห็นคำตอบนี้

เพื่อให้บรรลุการเปลี่ยนแปลงเหล่านี้ฉันจะทำสิ่งต่อไปนี้:

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)


การทดสอบ / 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
ฉันเพิ่งสังเกตเห็นว่าคุณได้เพิ่มไฟล์. h ไปยังไฟล์ CMakeLists.txt ตามนั้น จำเป็นหรือไม่ และจะเกิดอะไรขึ้นหากฉันทิ้งพวกเขาไป?
Grzenio

3
@Grzenio นี่เป็นเพียงคุณสมบัติความสะดวกสบาย - มันปรากฏใน IDE ของ IDEVC เหมือนเป็นส่วนหนึ่งของเป้าหมาย แต่ไม่เช่นนั้นจะไม่มีผลกระทบ
เฟรเซอร์

1
TEST_SOURCE_DIR ตั้งอยู่ที่ไหน
aggsol

6
มันถูกตั้งค่าโดย CMake โดยอัตโนมัติเมื่อมีการโทรproject (TEST)- ดูcmake.org/cmake/help/v3.6/variable/PROJECT-NAME_SOURCE_DIR.html
Fraser

> พวกเขาปรากฏใน IDE เช่น MSVC ซึ่งเป็นส่วนหนึ่งของเป้าหมาย --- MSVC ไม่สนับสนุนการทำเครื่องหมายไดเรกทอรีด้วยส่วนหัวว่า "รวมไดเรกทอรี" หรือไม่
isnullxbh

46

ฉันชอบตัวอย่างของ @Fraser แต่จะใช้คำสั่ง add_test ในการทดสอบ / CMakeLists.txt และใช้ enable_testing ก่อน add_subdirectory (ทดสอบ)

วิธีนี้คุณสามารถเรียกใช้การทดสอบของคุณจากไดเรกทอรีการสร้างระดับบนสุดในขณะที่ระบุการทดสอบของคุณใน test / CMakeLists.txt

ผลลัพธ์จะมีลักษณะดังนี้ (ฉันนำตัวอย่าง @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)

การทดสอบ / 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
ขอบคุณฉันไม่พบการทดสอบผ่านctest -Nจนกว่าคุณจะได้รับคำแนะนำเกี่ยวกับการเปิดใช้งานการทดสอบก่อนที่จะเพิ่ม subdir
alaferg

@alaferg: มิฉะนั้นพวกเขาจะจบลงในการทดสอบย่อยในการสร้าง dir
gauteh

4
ฉันหวังว่า CMake จะมีบางอย่างที่คล้ายกับโครงสร้าง
ruipacheco
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.