Pergunta

Eu gostaria de passar algumas opções para um compilador.A opção teria que ser calculado em tempo de compilação - sempre quando 'fazer' é invocado, e não quando 'cmake', então execute_process comando não cortá-lo.(não é?)

Por exemplo, passar uma data para um compilador g++ assim:

g++ prog.cpp -o prog -DDATETIME="17:09:2009,14:25"

Mas com data / hora, calculado em tempo de compilação.

Alguma idéia de como fazê-lo no CMake?

Recompensa editar:

Pelo menos hackish solução será aceito.

Por favor note que eu quero ser capaz de exectue um comando arbitrário em tempo de compilação, não apenas 'data'.

Edit 2:

Ele tem que trabalhar em Linux, Windows (VS), Mingw, o Cygwin e o mac OS X.Você não pode assumir Ruby, Perl ou Python como eles não são padrão no Windows.Você pode assumir BOOST, mas eu acho que não.

O objetivo é forçar o cmake para gerar o Makefile (no caso do Linux) o que fazer quando é executado, irá fazer o trabalho.

Criação personalizada *.h arquivo está ok, mas tem que ser iniciada por um Makefile (ou equivalente em outro sistema operacional) por fazer.A criação de *.h não precisa (e não deve) usar o cmake.

Foi útil?

Solução

Você está deixando de fora algumas informações, como quais plataformas você precisa para executar este e se existem ferramentas adicionais que você pode usar.Se você pode usar Ruby, Perl, Python, as coisas se tornam muito mais simples.Eu vou suponha que você deseja executar no Unix e Windows pqlatform e de que não existem ferramentas adicionais disponíveis.

Se você deseja que a saída do comando em um símbolo de pré-processamento, o a maneira mais fácil é para gerar um arquivo de cabeçalho, em vez de brincar com parâmetros de linha de comando.Lembre-se de que o CMake tem um script de modo (-P), onde só processa comandos de script no arquivo, de modo que você pode fazer algo como isto:

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)

O arquivo "personalizado.h" é gerado em tempo de compilação através do comando "cmake -P personalizado.o cmake".personalizado.o cmake parecido com este:

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

Ele executa o comando (neste caso, "uname-a", você vai substituí-lo com qualquer comando que você deseja), e coloca o resultado na variável _output, que, em seguida, grava personalizado.h.Note que isto apenas irá trabalho se o comando saídas de uma única linha.(Se você precisar de várias linhas de saída, você vai ter que escrever um mais personalizado complexo.o cmake, dependendo como você quer que as várias linhas de dados em seu programa.)

O principal programa parecido com este:

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

Se você realmente deseja para calcular opções de compilador em tempo de compilação, as coisas tornam-se muito mais complicado.Para Bourne-shell geradores você pode apenas insira o comando dentro de aspas para traz.Se você ficar louco ao mesmo tempo descobrir citando, mover toda a lógica de seu comando dentro de um shell-script para você só precisa colocar o mycommand.sh em seu add_definitions():

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

Para Windows ficheiro batch com base geradores coisas são muito mais complicada, e eu não tem uma boa solução.O problema é que o PRE_BUILD comandos não são executados como parte do mesmo arquivo em lotes como o compilador real invocação (estudo a BuildLog.htm para mais detalhes), então a minha idéia inicial não trabalho (geração de um costume.morcego em um PRE_BUILD passo e, em seguida, fazer "chamar personalizado.bat" sobre ele para obter um conjunto de variáveis que podem, posteriormente, ser referenciados na linha de comando do compilador).Se existe um equivalente de aspas para traz em arquivos em lotes, que iria resolver o problema.

Espero que este dá algumas ideias e pontos de partida.

(Agora para o inevitável contra-pergunta:o que são você realmente tentando fazer?)

EDITAR:Eu não sei por que você não quer que o CMake ser usado para gerar o cabeçalho do arquivo.Usando o ${CMAKE_COMMAND} vai se expandir para o CMake usado para gerar Makefiles/.vcproj-arquivos, e uma vez que o CMake não realmente de suporte portátil Makefiles/.vcproj-arquivos será necessário executar novamente o CMake as máquinas de destino.

O CMake também tem um monte de utilitário de comandos (Executar o "cmake -E" para uma lista), por este motivo explícito.Você pode por exemplo fazer

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

para copiar arquivo1.h para arquivo2.h.

De qualquer maneira, se você não deseja gerar o cabeçalho de arquivos utilizando o CMake, você nem precisa chamar separado .bat/.sh scripts para gerar o arquivo de cabeçalho, ou fazê-lo usando o comando " echo:

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

Ajustar citando como necessário.

Outras dicas

A solução acima (usando um separado do CMake arquivo de script para gerar um arquivo de cabeçalho) parece muito flexível, mas um pouco complicado para o que está sendo feito no exemplo.

Uma alternativa é definir um COMPILE_DEFINITIONS propriedade de um indivíduo e de ficheiro de origem ou de destino, caso em que o definido pelo pré-processador de variáveis só será definido para o ficheiro ou ficheiros de origem de destino são compilados.

O COMPILE_DEFINITIONS propriedades têm um formato diferente do que o usado no add_definitions de comando, e tem a vantagem que você não precisa se preocupar "-D" ou "\D" sintaxe e eles funcionam de plataforma cruzada.

Código de exemplo

-- CMakeLists.txt --

execute_process(COMMAND svnversion
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
    OUTPUT_VARIABLE SVN_REV)
string(STRIP ${SVN_REV} SVN_REV)

execute_process(COMMAND date "+%Y-%m-%d-%H:%M"
    OUTPUT_VARIABLE BUILD_TIME)
string(STRIP ${BUILD_TIME} BUILD_TIME)

set_source_files_properties(./VersionInfo.cpp
    PROPERTIES COMPILE_DEFINITIONS SVN_REV=\"${SVN_REV}\";BUILD_TIME=\"${BUILD_TIME}\"")

A primeira linha executa um comando do shell svnversion e coloca o resultado na variável SVN_REV.O string(STRIP ...) comando é necessário para remover à direita os caracteres de nova linha de saída.

Nota isto partindo do princípio de que o comando a ser executado é multi-plataforma.Se não, você pode precisar de ter alternativas para diferentes plataformas.Por exemplo, eu uso o cygwin implementação do Unix date de comando, e tem:

if(WIN32)
 execute_process(COMMAND cmd /C win_date.bat
    OUTPUT_VARIABLE BUILD_TIME)
else(WIN32)
  execute_process(COMMAND date "+%Y-%m-%d-%H:%M"
    OUTPUT_VARIABLE BUILD_TIME)
endif(WIN32)
string(STRIP ${BUILD_TIME} BUILD_TIME)

para a data de comandos, onde win_date.bat é um arquivo bat que indique a data no formato desejado.

Os dois pré-processador de variáveis não estão disponíveis no arquivo ./VersionInfo.cpp mas não em outros arquivos.Em seguida, você poderia ter

-- VersionInfo.cpp --

std::string version_build_time=BUILD_TIME;
std::string version_svn_rev=SVN_REV;

Isso parece funcionar muito bem em plataformas e minimiza a quantidade de código específico da plataforma.

Eu usaria a seguinte abordagem:

  1. Crie um executável que imprima a data atual para Stdout (o CMake não possui essa funcionalidade)
  2. Adicione um alvo que seja sempre considerado desatualizado
  3. Deixe o alvo invocar outro script cmake
  4. Deixe o script cmake invocado gerar um arquivo de cabeçalho

Exemplo Código para isso:

--- 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)

--- Gereate.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)

--- Gereate.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;
}

Isso resulta em um cabeçalho "gerado.h" que é regenerado em todas as compilações. Se você não precisar do DateTime, este exemplo pode ser substancialmente simplificado, pois o CMake não possui esse recurso e um programa deve ser criado para simular a funcionalidade.

No entanto, eu pensaria mais que duas vezes antes de fazer isso. Lembre-se de que o arquivo de cabeçalho será regenerado toda vez que for executado, tornando seu alvo inválido em tudo vezes. Você irá Nunca Tenha um binário considerado atualizado.

Isto funciona?

d=`perl -e"print qq(Whatever calculated at runtime);"`; g++ prog.cpp -o prog -DDATETIME=$$d
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top