Как выполнить команду во время компиляции в Make-файле, сгенерированном CMake?

Повышение. Поток имеет, так как выпуск 1.35.0 уже поддерживает блокировки читателя-писателя. Хорошая вещь об этом состоит в том, что реализация является значительно межплатформенной, рецензируемой, и на самом деле ссылочная реализация для предстоящего C++ 0x стандарт .

33
задан Mark Lakata 29 July 2014 в 21:38
поделиться

3 ответа

Вы упускаете некоторую информацию, например, какие платформы вам нужны чтобы запустить это, и есть ли какие-либо дополнительные инструменты, которые вы можете использовать. Если вы можете использовать Ruby, Perl или Python, все становится намного проще. Больной предположим, что вы хотите работать как на pqlatform Unix, так и на Windows, и что нет доступных дополнительных инструментов.

Если вы хотите, чтобы выходные данные команды были в символе препроцессора, Самый простой способ - создать файл заголовка вместо того, чтобы возиться с параметрами командной строки. Помните, что CMake имеет режим сценария (-P), где он обрабатывает только команды сценария в файле, поэтому вы можете сделайте что-нибудь вроде этого:

CMakeLists.txt:

project(foo)  
cmake_minimum_required(VERSION 2.6)
add_executable(foo main.c custom.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})  
add_custom_command(OUTPUT custom.h 
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/custom.cmake)

Файл "custom.h" создается во время компиляции командой "cmake -P custom.cmake ". Custom.cmake выглядит так:

execute_process(COMMAND uname -a 
    OUTPUT_VARIABLE _output OUTPUT_STRIP_TRAILING_WHITESPACE)
file(WRITE custom.h "#define COMPILE_TIME_VALUE \"${_output}\"")

Он выполняет команду (в данном случае" uname -a ", вы замените ее любой командой по вашему желанию) и помещает результат в переменную _output, который затем записывается в custom.h. Обратите внимание, что это будет только работают, если команда выводит одну строку. (Если вам нужен многострочный вывод, вам придется написать более сложный custom.cmake, в зависимости от как вы хотите, чтобы многострочные данные были в вашей программе.)

Основная программа выглядит так:

#include <stdio.h>
#include "custom.h"
int main()
{
  printf("COMPILE_TIME_VALUE: %s\n", COMPILE_TIME_VALUE);
  return 0;
}

Если вы действительно хотите вычислить параметры компилятора во время компиляции, все становится намного сложнее. Для генераторов оболочки Борна вы можете просто вставьте команду внутри обратных кавычек. Если вы рассердитесь, выясняя цитируя, переместите всю логику вашей команды внутрь сценария оболочки, чтобы вам нужно только поместить mycommand.sh в свой add_definitions ():

if(UNIX)
  add_definitions(`${CMAKE_CURRENT_SOURCE_DIR}/custom-options.sh`)
endif()

Для генераторов на основе командных файлов Windows все гораздо сложнее, и я нет хорошего решения. Проблема в том, что команды PRE_BUILD не выполняются как часть того же командного файла, что и фактический компилятор вызов (подробности см. в BuildLog.htm), поэтому моя первоначальная идея не сработало (создание custom.bat на этапе PRE_BUILD , а затем выполните "вызовите custom.bat", чтобы получить набор переменных, который позже может быть упоминается в командной строке компилятора). Если есть эквивалент обратные кавычки в пакетных файлах, которые решат проблему.

Надеюсь, это даст некоторые идеи и отправные точки.

(Теперь к неизбежному встречному вопросу: кто вы на самом деле пытаетесь сделать?)

РЕДАКТИРОВАТЬ: Я не уверен, почему вы не хотите, чтобы CMake использовался для генерации файла заголовка. Использование $ {CMAKE_COMMAND} расширится до CMake, используемого для создания файлов Makefiles / .vcproj, и, поскольку CMake на самом деле не поддерживает переносимые файлы Makefiles / .vcproj, вам нужно будет повторно запустить CMake на целевых машинах.

CMake также имеет набор служебных команд (запустите «cmake -E» для получения списка) по этой явной причине. Вы можете, например, сделать

add_custom_command(OUTPUT custom.h COMMAND ${CMAKE_COMMAND} -E copy file1.h file2.h)

, чтобы скопировать file1.h в file2.h.

В любом случае, если вы не хотите создавать файлы заголовков с помощью CMake, вам нужно будет либо вызвать отдельный .bat / .sh сценарии для генерации файла заголовка или сделайте это с помощью echo:

add_custom_command(OUTPUT custom.h COMMAND echo #define SOMETHING 1 > custom.h)

Настройте цитирование по мере необходимости.

45
ответ дан 27 November 2019 в 18:26
поделиться

Это работает?

d=`perl -e"print qq(Whatever calculated at runtime);"`; g++ prog.cpp -o prog -DDATETIME=$$d
-1
ответ дан 27 November 2019 в 18:26
поделиться

Я бы использовал следующий подход :

  1. Создать исполняемый файл, который выводит текущую дату на стандартный вывод (в CMake эта функция отсутствует)
  2. Добавить цель, которая всегда считается устаревшей
  3. Разрешить цели вызывать другой сценарий CMake
  4. Разрешить запущенному CMake сценарий генерирует файл заголовка

Пример кода для этого:

--- CMakeLists.txt ---

PROJECT(Foo)
ADD_EXECUTABLE(RetreiveDateTime ${CMAKE_CURRENT_SOURCE_DIR}/datetime.cpp)
ADD_CUSTOM_TARGET(GenerateFooHeader
                  COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/Generate.cmake
                  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                  DEPENDS RetreiveDateTime)
ADD_EXECUTABLE(Foo "test.cpp" "${CMAKE_CURRENT_BINARY_DIR}/generated.h")
ADD_DEPENDENCIES(Foo GenerateFooHeader)

--- Generate.cmake ---

EXECUTE_PROCESS(COMMAND ${CMAKE_BINARY_DIR}/RetreiveDateTime OUTPUT_VARIABLE DATETIMESTRING)
MESSAGE(STATUS "DATETIME=\"${DATETIMESTRING}\"")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated.h @ONLY)

--- generate.h.in - -

#pragma once

#define DATETIMESTRING "@DATETIMESTRING@"

--- datetime.cpp ---

#include <iostream>
#include <ctime>
#include <cstring>

int main(int, char*[])
{
 time_t now;
 time(&now);
 tm * timeinfo = localtime(&now);

 char * asstring = asctime(timeinfo);
 asstring[strlen(asstring) - 1] = '\0'; // Remove trailing \n
 std::cout << asstring;
 return 0;
}

--- test.cpp ---

#include "generated.h"

#include <iostream>

int main(int, char*[])
{
 std::cout << DATETIMESTRING << std::endl;
 return 0;
}

В результате получается заголовок "generated.h", который восстанавливается при каждой сборке. Если вам не нужно DATETIME, этот пример можно существенно упростить, поскольку в CMake эта функция отсутствует, и необходимо создать программу для моделирования этой функции.

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

2
ответ дан 27 November 2019 в 18:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: