CMake: struttura del progetto con unit test


139

Sto cercando di strutturare il mio progetto in modo da includere le fonti di produzione (nella srcsottocartella) e i test (nella testsottocartella). Sto usando CMake per costruire questo. Come esempio minimo ho i seguenti file:

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 - usa sqr, non importa

test / 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 / 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));
}

Alcune domande:

  1. Questa struttura ha senso? Quali sono le migliori pratiche per strutturare questo codice? (Vengo da C # e Java, e lì è più facile in un certo senso)
  2. Non mi piace il fatto che devo elencare tutti i file dalla srccartella nel test/CMakeLists.txtfile. Se questo fosse un progetto di biblioteca, collegherei semplicemente la biblioteca. C'è un modo per evitare di elencare tutti i file cpp dall'altro progetto?
  3. Quali sono le linee enable_testing()e le add_test(MyTest test)azioni? Non ho visto alcun effetto. Come posso eseguire i test da CMake (o CTest)?
  4. Finora ho appena eseguito cmake .nella cartella principale, ma questo ha creato un casino con file temporanei ovunque. Come posso ottenere i risultati della compilazione in una struttura ragionevole?

Mi considero un principiante di CMake, quindi non so quali siano le migliori pratiche accettate, ma FWIW farei una libreria "sqr" * su cui dipendevano sia il main che il test. (* o suo equivalente morale)
user786653

Risposte:


125

Per le domande 1 e 2, consiglierei di creare una libreria dai tuoi file non di prova escludendo main.cpp (in questo caso solo src / sqr.cpp e src / sqr.h), e quindi puoi evitare l'elenco (e, soprattutto, ricompilare) tutte le fonti due volte.

Per la domanda 3, questi comandi aggiungono un test chiamato "MyTest" che invoca il "test" eseguibile senza alcun argomento. Tuttavia, poiché hai aggiunto questi comandi a test / CMakeLists.txt e non al tuo CMakeLists.txt di livello superiore, puoi solo invocare il test all'interno della sottodirectory "test" del tuo albero di build (prova cd test && ctest -N). Se si desidera che il test sia eseguibile dalla directory di build di livello superiore, è necessario chiamare add_testdal CMakeLists.txt di livello superiore. Questo significa anche che devi usare la forma più dettagliata di add_testpoiché il tuo exe di prova non è definito nella stessa CMakeLists.txt

Nel tuo caso, poiché stai eseguendo cmake nella cartella principale, l'albero della build e l'albero dei sorgenti sono la stessa cosa. Questo è noto come build in-source e non è l'ideale, il che porta alla domanda 4.

Il metodo preferito per generare l'albero di compilazione è fare un build fuori dal sorgente, ovvero creare una directory da qualche parte al di fuori del tuo albero dei sorgenti ed eseguire cmake da lì. Anche la creazione di una directory "build" nella radice del progetto e l'esecuzione cmake ..forniranno una struttura pulita che non interferirà con l'albero dei sorgenti.

Un ultimo punto è quello di evitare di chiamare i file eseguibili "test" (con distinzione tra maiuscole e minuscole). Per i motivi, vedi questa risposta .

Per ottenere questi cambiamenti, farei quanto segue:

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)


test / 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
Ho appena notato che hai aggiunto anche i file .h ai file CMakeLists.txt di conseguenza. È richiesto? E cosa accadrebbe se li lasciassi fuori?
Grzenio,

3
@Grzenio Questa è solo una funzione di praticità: appaiono in IDE come MSVC come parte del target, ma per il resto questo non ha alcun effetto.
Fraser,

1
Dove è impostato TEST_SOURCE_DIR?
aggsol,

6
Viene impostato automaticamente da CMake durante la chiamata project (TEST)- vedi cmake.org/cmake/help/v3.6/variable/PROJECT-NAME_SOURCE_DIR.html
Fraser,

> compaiono negli IDE come MSVC come parte del target --- MSVC non supporta il contrassegno della directory con le intestazioni come "include directory"?
isnullxbh,

46

Mi piace l'esempio di @Fraser ma userei il comando add_test nel test / CMakeLists.txt e utilizzerei enable_testing prima di add_subdirectory (test).

In questo modo è possibile eseguire i test dalla directory di build di livello superiore specificando i test in test / CMakeLists.txt.

Il risultato sarebbe simile al seguente (ho riutilizzato l'esempio di @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)

test / 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
Grazie, non ho mostrato alcun test ctest -Nfino a quando non hai il consiglio di abilitare il test prima di aggiungere il sottodir.
alaferg,

@alaferg: altrimenti finirebbero nel sottodirectory test all'interno della dir build.
gauteh,

4
Vorrei che CMake avesse qualcosa che somigliasse alla struttura.
Ruipacheco,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.