Я сделал MCVE для примера приложения (App/app.cc
) с исходным кодом не на C ++ (App/text.txt
), который должен быть скомпилирован с использованием промежуточных источников C ++.
Пример дерева каталогов:
└┬─ ./
├─── CMakeLists.txt
├─┬─ App/
│ ├─── CMakeLists.txt
│ ├─── app.cc
│ └─── text.txt
└─┬─ Tool/
├─── CMakeLists.txt
└─── tool.cc
Файл ./CMakeLists.txt
является основным файлом проекта (предоставляет решение для VisualStudio):
project(App)
cmake_minimum_required(VERSION 3.10.0)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_subdirectory(App)
add_subdirectory(Tool)
Исходный код ./Tool/tool.cc
для сборкиинструмент для создания исходного кода C ++ и заголовка из текстового файла:
// a sample tool converting a text file to a c++ source
#include <fstream>
#include <iostream>
#include <string>
int main(int argc, char **argv)
{
if (argc < 3) {
std::cerr <<
"ERROR in tool: Missing arguments!\n"
"\n"
"Usage:\n"
"tool TXT_FILE CC_FILE\n";
return -1;
}
std::ifstream fIn(argv[1]);
if (!fIn.good()) {
std::cerr << "ERROR: Cannot open '" << argv[1] << "' for reading!\n";
return -1;
}
const std::string fileH = std::string(argv[2]) + ".h";
std::ofstream fOutH(fileH);
if (!fOutH.good()) {
std::cerr << "ERROR: Cannot open '" << fileH << "' for writing!\n";
return -1;
}
const std::string fileCC = std::string(argv[2]) + ".cc";
std::ofstream fOutCC(fileCC);
if (!fOutCC.good()) {
std::cerr << "ERROR: Cannot open '" << fileCC << "' for writing!\n";
return -1;
}
fOutCC << "#include \"" << fileH << "\"\n\n";
for (std::string buffer; std::getline(fIn, buffer);) {
const size_t i = buffer.find('=');
if (i < buffer.size()) {
fOutH << "extern const char *const " << buffer.substr(0, i) << ";\n";
fOutCC << "const char *const " << buffer.substr(0, i)
<< " = \"" << buffer.substr(i + 1) << "\";\n";
}
}
fOutH.close();
if (!fOutH.good()) {
std::cerr << "ERROR: Couldn't complete writing of '" << fileH << "'!\n";
return -1;
}
fOutCC.close();
if (!fOutCC.good()) {
std::cerr << "ERROR: Couldn't complete writing of '" << fileCC << "'!\n";
return -1;
}
return 0;
}
Файл ./Tool/CMakeLists.txt
для сборки инструмента:
project(Tool)
add_executable(tool
tool.cc)
set_property(TARGET tool
PROPERTY FOLDER "Tools")
Файл ./App/text.txt
- aтекстовый файл, который должен быть преобразован в сгенерированные источники text.cc
и text.h
:
text1=Hello World.
text2=Text built with tool -> VC++
Источник ./App/app.cc
, где включено text.h
:
// a sample app using an indirect built source file
#include <iostream>
#include "text.h"
int main()
{
std::cout << "text1: '" << text1 << "'\n";
std::cout << "text2: '" << text2 << "'\n";
return 0;
}
Наконец,./App/CMakeLists.txt
, который вводит пользовательский этап сборки:
# custom build step
add_custom_command(
OUTPUT
text.cc text.h
COMMAND
tool "${CMAKE_CURRENT_SOURCE_DIR}/text.txt" text
MAIN_DEPENDENCY
text.txt
DEPENDS
tool
COMMENT
"generate C++ sources from text"
VERBATIM)
# regular C++ build
add_executable(app
app.cc # regular source files
text.cc text.h) # intermediate source files
# add build dir for project to include directories
include_directories(app
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
Наличие DEPENDS tool
в add_custom_command
и OUTPUT
в add_custom_command
в add_executable
дает:
test.txt
указан как источник в VS-проекте app
- VS-проект
tool
включен в VS-решение App
tool
isсоставлено и связано,и затем используется для преобразования test.txt
в test.h
и test.cc
до того, как app
скомпилировано и скомпоновано (успешно).
Сгенерированные промежуточные источники появляются в каталоге сборки (незагрязнять исходный каталог).Следовательно, каталог сборки также должен быть задан как include-путь.В противном случае #include "text.h"
(в app.cc
) не будет работать.