CMake e CTest: make test non crea test


89

Sto provando CTest in CMake per eseguire automaticamente alcuni dei miei test utilizzando make testtarget. Il problema è che CMake non "capisce" che il test che sono disposto a eseguire deve essere compilato poiché fa parte del progetto.

Quindi sto cercando un modo per specificare esplicitamente questa dipendenza.

Risposte:


79

È senza dubbio un bug in CMake (precedentemente tracciato qui ) che questo non funziona immediatamente. Una soluzione alternativa è eseguire le seguenti operazioni:

add_test(TestName ExeName)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}
                  DEPENDS ExeName)

Quindi puoi eseguire make checke compilerà ed eseguirà il test. Se hai diversi test, dovresti usare DEPENDS exe1 exe2 exe3 ...nella riga sopra.


1
quindi immagino che l'obiettivo "make test" rimarrà inutilizzato in quanto sembra che tu debba scegliere un nome di destinazione diverso nel comando add_custom_target?
claf

Sì. L'unica differenza tra "make test" e "make check" è che il primo mostra "Esecuzione di test ..." prima e non controlla le dipendenze di compilazione.
richq

2
@rq - ma come posso farlo con più progetti (quando un CMakeLists.txt è un sottoprogetto di un altro) in modo che ognuno definisca il checktarget e potrebbero scontrarsi
Artyom

2
@Artyom - in questo caso probabilmente è meglio usare l'equivalente "make all test". In effetti, questo è quello che faccio comunque.
richq

4
In realtà, alcuni lo considerano una funzionalità (non un bug) di cmake che puoi eseguire "make test" ed eseguire i test così come sono senza prima fare alcuna ricostruzione ...
DLRdave

55

In realtà c'è un modo per usare make test. È necessario definire la build dell'eseguibile di test come uno dei test e quindi aggiungere le dipendenze tra i test. Questo è:

ADD_TEST(ctest_build_test_code
         "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target test_code)
ADD_TEST(ctest_run_test_code test_code)
SET_TESTS_PROPERTIES(ctest_run_test_code
                     PROPERTIES DEPENDS ctest_build_test_code)

11
Questo è l'unico che aumenta e non ti obbliga a costruire gli obiettivi "crea tutto" solo per eseguire il test. Un possibile svantaggio: i dettagli degli errori di compilazione sui binari vengono visualizzati solo nel file LastTest.log generato e non su stdout / stderr
Dave Abrahams

2
Buona risposta! Tuttavia, dovresti aggiungere la configurazione alla destinazione della build. Altrimenti non è possibile eseguire i test in tutte le configurazioni. add_test (NAME "$ {ARGV0} _BUILD" COMMAND "$ {CMAKE_COMMAND}" --build $ {CMAKE_BINARY_DIR} --target $ {target} "--config" "$ <CONFIG>")
Daniel

1
Questo intasa il giornalista del test con un mucchio di test fasulli.

Se stai usando CMake> = 3.7, l'approccio consigliato è usare i dispositivi. Vedi la mia risposta di seguito.
John Freeman

13

Uso una variante della risposta di richq. Nel livello superiore CMakeLists.txt, aggiungo un target personalizzato,, build_and_testper la creazione e l'esecuzione di tutti i test:

find_package(GTest)
if (GTEST_FOUND)
    enable_testing()
    add_custom_target(build_and_test ${CMAKE_CTEST_COMMAND} -V)
    add_subdirectory(test)
endif()

Nei vari CMakeLists.txtfile di sottoprogetto sotto test/, aggiungo ogni eseguibile di test come dipendenza di build_and_test:

include_directories(${CMAKE_SOURCE_DIR}/src/proj1)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(proj1_test proj1_test.cpp)
target_link_libraries(proj1_test ${GTEST_BOTH_LIBRARIES} pthread)
add_test(proj1_test proj1_test)
add_dependencies(build_and_test proj1_test)

Con questo approccio, ho solo bisogno make build_and_testdi make test(o make all test), e ha il vantaggio di creare solo codice di test (e le sue dipendenze). È un peccato non poter usare il nome del bersaglio test. Nel mio caso, non è così male perché ho uno script di primo livello che esegue il debug e il rilascio fuori dall'albero (e le compilazioni incrociate) chiamando cmakee poi make, e si traduce testin build_and_test.

Ovviamente, la roba GTest non è richiesta. Mi è capitato di usare / come Google Test e volevo condividere un esempio completo di utilizzo con CMake / CTest. IMHO, questo approccio ha anche il vantaggio di consentirmi di utilizzare ctest -V, che mostra l'output di Google Test durante l'esecuzione dei test:

1: Running main() from gtest_main.cc
1: [==========] Running 1 test from 1 test case.
1: [----------] Global test environment set-up.
1: [----------] 1 test from proj1
1: [ RUN      ] proj1.dummy
1: [       OK ] proj1.dummy (0 ms)
1: [----------] 1 test from proj1 (1 ms total)
1:
1: [----------] Global test environment tear-down
1: [==========] 1 test from 1 test case ran. (1 ms total)
1: [  PASSED  ] 1 test.
1/2 Test #1: proj1_test .......................   Passed    0.03 sec

In questo esempio, c'è un modo per fare in modo che make test faccia ciò che fa ctest -V invece di ctest? L'output di ctest sembra molto incompleto e dice solo che esiste un singolo test.
Rajiv

6

Se stai cercando di emulare make check, potresti trovare utile questa voce wiki:

http://www.cmake.org/Wiki/CMakeEmulateMakeCheck

Ho appena verificato che fa quello che dice con successo (CMake 2.8.10).


1
Questo creerà tutti gli eseguibili durante l'esecuzione make check. Per i test con tempi di compilazione dominanti, questo è ctest -Rinutile.
usr1234567

4

Risparmia il mal di testa:

make all test

Per me funziona immediatamente e creerà dipendenze prima di eseguire il test. Dato quanto sia semplice, rende quasi make testconveniente la funzionalità nativa perché ti dà la possibilità di eseguire gli ultimi test di compilazione anche se il tuo codice è rotto.


1
Non funziona con CDash. Devi chiamare make all && ctest e quindi l'edificio non fa parte del test caricato. Quindi gli avvisi o gli errori di build non sono visibili.
usr1234567

2
Inoltre non funziona bene se si desidera una build parallela, poiché i due verranno eseguiti in parallelo: è necessario make -j4 all && make test. Ed è anche traballante usando uno strumento di build non Make.
poolie

4

Se stai usando CMake> = 3.7, l'approccio consigliato è usare i dispositivi :

add_executable(test test.cpp)
add_test(test_build
  "${CMAKE_COMMAND}"
  --build "${CMAKE_BINARY_DIR}"
  --config "$<CONFIG>"
  --target test
)
set_tests_properties(test_build PROPERTIES FIXTURES_SETUP    test_fixture)
add_test(test test)
set_tests_properties(test       PROPERTIES FIXTURES_REQUIRED test_fixture)

Questo fa quanto segue:

  • Aggiunge una testdestinazione eseguibile costruita datest.cpp
  • Aggiunge un test_build"test" che esegue Cmake per costruire il targettest
  • Contrassegna il test_buildtest come un'attività di configurazione del dispositivotest_fixture
  • Aggiungi un testtest che esegue solo l' testeseguibile
  • Contrassegna il testtest per aver bisogno del dispositivo test_fixture.

Quindi, ogni volta che testdeve essere eseguito test test_build, esegue prima test , che crea l'eseguibile necessario.


Se $<CONFIG>non è impostato --target, diventerà l'argomento di --config.
loshad vtapkah

Credo $<CONFIG>sia sempre non vuoto. È un'espressione generatrice per il nome della configurazione: cmake.org/cmake/help/latest/manual/… Modificherò la risposta per racchiuderla comunque tra virgolette solo perché non fa differenza.
John Freeman

Come corri cmake? Lo faccio in questo modo: mkdir build; cd build; cmake ..; make. E sembra che non ci siano valori predefiniti e tutte le variabili correlate sono vuote, fino a quando non CMAKE_BUILD_TYPEviene impostato manualmente. (attualmente su Debian 10, non ha controllato altre piattaforme)
loshad vtapkah

1

Questo è ciò che ho elaborato e ho utilizzato:

set(${PROJECT_NAME}_TESTS a b c)

enable_testing()
add_custom_target(all_tests)
foreach(test ${${PROJECT_NAME}_TESTS})
        add_executable(${test} EXCLUDE_FROM_ALL ${test}.cc)
        add_test(NAME ${test} COMMAND $<TARGET_FILE:${test}>)
        add_dependencies(all_tests ${test})
endforeach(test)

build_command(CTEST_CUSTOM_PRE_TEST TARGET all_tests)
string(CONFIGURE \"@CTEST_CUSTOM_PRE_TEST@\" CTEST_CUSTOM_PRE_TEST_QUOTED ESCAPE_QUOTES)
file(WRITE "${CMAKE_BINARY_DIR}/CTestCustom.cmake" "set(CTEST_CUSTOM_PRE_TEST ${CTEST_CUSTOM_PRE_TEST_QUOTED})" "\n")

YMMV


0

La risposta di Derrick, semplificata e commentata:

# It is impossible to make target "test" depend on "all":
# https://gitlab.kitware.com/cmake/cmake/-/issues/8774
# Set a magic variable in a magic file that tells ctest
# to invoke the generator once before running the tests:
file(WRITE "${CMAKE_BINARY_DIR}/CTestCustom.cmake"
    "set(CTEST_CUSTOM_PRE_TEST ${CMAKE_MAKE_PROGRAM})\n"
)

Non è perfettamente corretto, in quanto non risolve il problema della concorrenza dell'esecuzione ninja all test, nel caso qualcuno lo facesse. Al contrario, perché ora hai due processi ninja.

(Ftr, ho anche condiviso questa soluzione qui .)


-3

Tutte le risposte di cui sopra sono perfette. Ma in realtà CMake usa CTest come strumento di test, quindi il metodo standard (penso che sia) per svolgere la missione è:

enable_testing ()
add_test (TestName TestCommand)
add_test (TestName2 AnotherTestCommand)

Quindi esegui cmake e make per costruire i bersagli. Dopodiché, puoi eseguire make test o semplicemente eseguire

ctest

otterrai il risultato. Questo è testato con CMake 2.8.

Controlla i dettagli su: http://cmake.org/Wiki/CMake/Testing_With_CTest#Simple_Testing


5
Downvoted perché a volte si desidera costruire solo gli obiettivi richiesti per i test effettivamente eseguiti.
Dave Abrahams

12
Questa risposta sembra fraintendere la domanda: L'OP sta già facendo esattamente come questa risposta raccomanda: Usando CTest, enable_testing(), add_test(), ecc Il problema è che deve emettere manualmente il comando build prima di eseguire i test. Vuole che l' make testobiettivo crei automaticamente gli eseguibili di test, se necessario.
bames53

-4

Tutte le risposte sono buone, ma implicano una violazione della tradizione per eseguire un test per comando make test. Ho fatto questo trucco:

add_test(NAME <mytest>
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMAND sh -c "make <mytarget>; $<TARGET_FILE:<mytarget>>")

Ciò significa che il test consiste nella creazione (facoltativamente) e nell'esecuzione di un target eseguibile.


6
:-D Regola # 1: non usare il sistema senza sh. Conosci questo sistema?
dyomas

11
Sì, Windows è uno di questi.
David Faure

3
Questo è anche hardcoded makee perde la funzionalità di CMake di generare script per altri strumenti di compilazione.
poolie
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.