Cmake - Как скопировать файлы с входными данными для создания выходной папки

Я использую CLion и CMake для создания проекта. Я создал конфигурацию сборки Google Test, и дерево моего проекта выглядит так:

дерево проекта

Тесты для токенизатора просты: токенизатор должен открывать исходные файлы и выводить токены.

Это мой файл CMakeLists.txt для tokenizer_test:

include_directories(${gtest_SOURCE_DIRS}/include ${gtest_SOURCE_DIRS})
add_subdirectory(test_src)
add_executable(run_tokenizer_tests
    tokenizer_test.cpp ${CMAKE_SOURCE_DIR}/includes/tokenizer.h
    ${CMAKE_SOURCE_DIR}/src/tokenizer.cpp
)

target_link_libraries(run_tokenizer_tests gtest gtest_main) 

Могу ли я разместить тестовые источники (например, 0.cpp на картинке) рядом с исполняемым файлом или мне нужно написать свои собственные сценарии тестирования? Как мне это сделать?


person Дмитрий Терехов    schedule 09.10.2017    source источник
comment
Взгляните на переменные CMake. Есть несколько, которые дают вам проектные и исходные каталоги, которые вы можете использовать для своих тестов (добавляя их как макросы при сборке или передавая в качестве аргументов при запуске тестов).   -  person Some programmer dude    schedule 09.10.2017
comment
@Someprogrammerdude, к сожалению, я ничего не нашел, поэтому написал это.   -  person Дмитрий Терехов    schedule 09.10.2017
comment
@ДмитрийТерехов, что вы подразумеваете под тестовыми источниками, что именно содержит 0.cpp? Входные данные для tokenizer_tests?   -  person Liastre    schedule 10.10.2017
comment
@Liastre это источник для токенизатора. Tokenizer берет исходный файл и выводит найденные токены (лексемы).   -  person Дмитрий Терехов    schedule 10.10.2017
comment
И как ваш токенизатор ожидает получить ввод?   -  person bgfvdu3w    schedule 10.10.2017
comment
@ДмитрийТерехов, как я понял, вы хотите разместить входные данные для теста (0.cpp), чтобы создать выходную папку на этапе настройки, верно?   -  person Liastre    schedule 10.10.2017
comment
@Liastre Я просто хочу иметь доступ к тестовым файлам (например, 0.cpp). Итак, я могу сделать что-то вроде файла в файлах, сделать исполняемый файл [args].   -  person Дмитрий Терехов    schedule 10.10.2017


Ответы (2)


Вы можете позвонить file(COPY source DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

См. https://cmake.org/Wiki/CMake_Useful_Variables для других переменных.

Вот фрагмент из нашего проекта, который делает это и многое другое.

В целом, этот фрагмент позволяет избежать зависимости от конкретных расположений файлов в файловой системе, при условии, что ваш каталог сборки активен, потому что пути к файлам будут жестко закодированы в ваших модульных тестах.

Это упрощает автоматическую сборку и проверку — не нужно отслеживать, куда cd перед вызовом средства запуска тестов.

Это также улучшает читаемость кода в модульных тестах.

CMakeLists.txt:

# list all test images

set(test_data

    origtest_config.h.in15Fps_3_27.png
    origtest_config.h.in15Fpstest_config.h.in34.png
    ....
)

# Loop over all items in the "test_data" list
# Copy PNG, JPEG and BMP images to the directory, where test binaries are created
# And generate full paths to them for hardcoding in the include file test_config.h

foreach(df ${test_data})

    # copy images to build dir

    if(${df} MATCHES "((jp|pn)g|bmp)$")
        file(COPY ${df} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})   
        set(df_file_path ${CMAKE_CURRENT_BINARY_DIR}/${df})
    else()
        set(df_file_path ${CMAKE_CURRENT_SOURCE_DIR}/${df}) 
    endif()

    # generate some C++ code in CMake variables IMAGE_PATHS and IMAGE_IDS
    # (see below)

    if (NOT IMAGE_PATHS)
        set(IMAGE_PATHS "    \"${df_file_path}\"")
    else()
        set(IMAGE_PATHS "${IMAGE_PATHS},\n    \"${df_file_path}\"")
    endif()

    string(REGEX REPLACE "[^a-zA-Z0-9]" "_" df_id ${df})

    if (NOT IMAGE_IDS)
        set(IMAGE_IDS "    img_${df_id}")
    else()
        set(IMAGE_IDS "${IMAGE_IDS},\n    img_${df_id}")
    endif()
endforeach()

set(TEST_PATH \"${CMAKE_CURRENT_BINARY_DIR}\")

configure_file(test_config.h.in test_config.h @ONLY)  # see below for test_config.h.in 

...
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )   # make test_config.h visible for compiler
add_executable (some_unit_test some_unit_test.cpp)
add_test(NAME some_unit_test COMMAND some_unit_test WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
 ... 
add_executable ( ... )
add_test(  ... )
...

Файл test_config.h.in.

/* DO NOT EDIT THIS FILE, IT IS AUTOGENERATED!
   All your changes will be overwritten.

   If you want to add new test data files, 
   add them to the `test_data` list in file CMakeLists.txt
*/ 

#ifndef __TEST_CONFIG_H__
#define __TEST_CONFIG_H__

const char* test_path = @TEST_PATH@; //!< full path to test data, without trailing slash

//! full paths to all test images
const char* image_paths[] = {
    @IMAGE_PATHS@
};

enum image_ids { //!< test file names, converted to enum constants
    @IMAGE_IDS@
};

#endif

Вызов configure_file заменяет @TEST_PATH@, @IMAGE_PATHS@ и @IMAGE_IDS@ их значениями.

Вот как выглядит сконфигурированный файл test_config.h в каталоге сборки.

/* DO NOT EDIT THIS FILE, IT IS AUTOGENERATED!
   All your changes will be overwritten.

   If you want to add new test data files, 
   add them to the `test_data` list in file CMakeLists.txt
*/ 

#ifndef __TEST_CONFIG_H__
#define __TEST_CONFIG_H__

const char* test_path = "F:/projects/project/build64/test"; //!< full path to test data, without trailing slash


//! full paths to all test images
const char* image_paths[] = {
  "F:/projects/project/build64/test/orig_5_15Fps_3_27.png",
  "F:/projects/project/build64/test/orig_5_15Fps_5_34.png",
   ... 
};

enum image_ids { //!< test file names, converted to enum constants
    img_orig_5_15Fps_3_27_png,
    img_orig_5_15Fps_5_34_png,
...
};

#endif

Использование в тестах:

#include "test_config.h"
....     
img0 = cv::imread(image_paths[img_orig_5_15Fps_3_27_png], cv::IMREAD_GRAYSCALE);

enum image_ids используется для удобочитаемой индексации в массиве image_paths. ИМХО, это намного лучше, чем image_paths[0], так как четко видно, какое изображение читается.

person wl2776    schedule 10.10.2017

Вы можете использовать функцию CMake configure_file с флагом COPYONLY. Он скопирует файл без замены каких-либо ссылок на переменные или другого содержимого. Ваш CMakeLists.txt рядом с tokenizer_test.cpp должен содержать:

configure_file(test_src/0.cpp 0.cpp COPYONLY)

P.S.: Я предлагаю вам переименовать каждый исходный файл и входной файл в соответствии с тестом, который вы делаете, в вашем случае 0.cpp следует назвать что-то вроде tokenizer_test_parse_input.cpp, и было бы лучше поместить этот файл рядом с `tokenizer_test.cpp".

person Liastre    schedule 10.10.2017