Frage

Ich möchte einige Optionen an einen Compiler zu übergeben. Die Option müßte bei der Kompilierung berechnet werden - jedes Mal, wenn ‚make‘ aufgerufen wird, nicht, wenn ‚cmake‘, so execute_process Befehl ist es nicht schneiden. (Oder?)

Zum Beispiel, ein Datum zu einem g ++ Compiler wie das geben:

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

Aber mit DATETIME- bei der Kompilierung berechnet.

Jede Idee, wie es in CMake zu tun?

Bounty edit:

A mindestens hackish Lösung akzeptiert werden.

Bitte beachten Sie, dass ich möchte einen beliebigen Befehl bei der Kompilierung zu exectue in der Lage sein, nicht nur ‚date‘.

Edit 2:

Es muss auf Linux, Windows (VS), Mingw, Cygwin und OS X arbeiten Sie können nicht Rubin, Perl oder Python übernehmen, da sie nicht Standard auf Windows sind. Sie können davon ausgehen, BOOST, aber ich denke, es ist nichts.

Das Ziel ist cmake zu zwingen Makefile zu generieren (im Fall von Linux), dass, wenn Make ausgeführt wird, wird die Arbeit machen.

Erstellen von benutzerdefinierten * .h-Datei ist in Ordnung, aber es hat von einem Makefile (oder gleichwertig auf anderen OS) nach Marke eingeleitet werden. Die Schaffung von * .h nicht haben (und sollte nicht) verwenden cmake.

War es hilfreich?

Lösung

Sie verlassen einige Informationen, wie zum Beispiel welche Plattformen Sie brauchen laufen diese auf und wenn es irgendwelche zusätzlichen Werkzeuge sind, können Sie verwenden. Wenn Sie Rubin, Perl, Python verwenden können, werden die Dinge viel einfacher. Krank davon ausgehen, dass Sie sowohl auf Unix- und Windows-pqlatform ausgeführt werden soll und dass es keine zusätzlichen Tools zur Verfügung stehen.

Wenn Sie die Ausgabe des Befehls in einem Präprozessorsymbol wollen, die einfachste Weg ist eine Header-Datei zu erzeugen, anstatt um Hantieren mit Befehlszeilenparametern. Denken Sie daran, dass CMake ein Skript-Modus hat (-P), wo es nur Skript verarbeitet Befehle in der Datei, so können Sie etwas tun, wie folgt aus:

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)

Die Datei „custom.h“ wird bei der Kompilierung durch den Befehl „cmake erzeugt . -P custom.cmake“custom.cmake sieht wie folgt aus:

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

Es den Befehl ausführt (in diesem Fall „uname -a“, Sie werden es ersetzen mit dem, was befehlen Sie mögen), und setzt den Ausgang in den Variablen _output, die es dann zu custom.h schreibt. Beachten Sie, dass dies nur arbeiten, wenn der Befehl eine Zeile ausgibt. (Wenn Sie mehrzeilige brauchen Ausgang, werden Sie eine komplexere custom.cmake schreiben, je nach wie Sie wollen die mehrzeilige Daten in Ihrem Programm.)

Das Hauptprogramm sieht wie folgt aus:

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

Wenn Sie wirklich wollen, um Compiler-Optionen bei der Kompilierung zu berechnen, Dinge werden viel schwieriger. Für Bourne-Shell-Generatoren können Sie einfach Einfügen des Befehls innerhalb Backticks. Wenn Sie wütend, während herauszufinden, zitiert, in einem Shell-Skript der gesamte Logik des Befehls bewegen, so Sie brauchen nur mycommand.sh in Ihrem add_definitions setzen ():

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

Für Windows-Batch-Datei-basierte Generatoren sind die Dinge viel tricker, und ich keine gute Lösung. Das Problem ist, dass die PRE_BUILD Befehle werden nicht als Teil der gleichen Batch-Datei als die eigentlichen Compiler ausgeführt Aufruf (Lernen der BuildLog.htm für Details), so meine Idee hat nicht funktioniert (eine custom.bat in einem PRE_BUILD Schritt zu erzeugen und dann tun „Call custom.bat“ auf einen Variable Satz zu erhalten, die später sein kann in der Compilerbefehlszeile verwiesen wird). Wenn es ein Äquivalent Backticks in Batch-Dateien, das würde das Problem lösen.

Hope dies gibt einige Ideen und Ansatzpunkte.

(jetzt auf die unvermeidlichen Gegenfrage: Was sind Sie auf wirklich versuchen zu tun?)

EDIT: Ich bin nicht sicher, warum Sie nicht wollen, lassen CMake die Header-Datei zu erzeugen, verwendet werden. Mit $ {CMAKE_COMMAND} wird erweitern, um die CMake die Makefiles / VCPROJ-Dateien zu erzeugen, verwendet wird, und da CMake nicht wirklich tragbar Makefiles / VCPROJ-Dateien unterstützen benötigen Sie CMake auf den Zielrechnern erneut ausführen.

CMake hat auch eine Reihe von Utility-Befehle (Run „cmake -E“ für eine Liste) für diesen expliziten Grund. Sie können zum Beispiel tun

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

file1.h zu file2.h kopieren.

Wie auch immer, wenn Sie nicht wollen, die Header-Dateien mit CMake zu generieren, müssen Sie entweder getrennte .bat / .sh Skripte aufrufen, um die Header-Datei zu erzeugen, oder es kann unter Verwendung von echo:

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

nach Bedarf zitieren.

Andere Tipps

Die Lösung oben (eine separate CMake Script-Datei mit einer Header-Datei zu erzeugen) scheint sehr flexibel, aber ein wenig kompliziert für das, was in diesem Beispiel getan wird.

Eine Alternative ist es, eine COMPILE_DEFINITIONS Eigenschaft setzen entweder auf einer einzelnen Quelldatei und oder Ziel, wobei in diesem Fall der definierten Vorprozessor Variablen nur für die Quelldatei oder Dateien im Ziel eingestellt wird zusammengestellt.

Die COMPILE_DEFINITIONS Eigenschaften haben ein anderes Format von dem im add_definitions Befehl verwendet, und haben den Vorteil, dass Sie nicht brauchen, um „-D“ oder „\ D“ Syntax und sie arbeiten plattformübergreifende Sorgen zu machen.

Beispiel-Code

- 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}\"")

Die erste Zeile läuft einen Shell-Befehl svnversion und legt das Ergebnis in der Variablen SVN_REV. Der string(STRIP ...) Befehl benötigt wird, um von den Ausgangshinterzeilenumbrüchen zu entfernen.

Beachten Sie dies unter der Annahme, dass der Befehl abgearbeitet wird plattformübergreifend. Wenn nicht müssen Sie Alternativen für verschiedene Plattformen haben. Zum Beispiel verwende ich die Cygwin-Implementierung des Unix date Befehl ein, und haben:

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)

für das Datum Befehl, wobei win_date.bat eine Fledermaus-Datei ist, die das Datum in dem gewünschten Format ausgibt.

Die beiden Pre-Prozessor-Variablen sind in der Datei ./VersionInfo.cpp nicht verfügbar, aber nicht in anderen Dateien festgelegt. Sie könnten dann haben

- VersionInfo.cpp -

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

Dies scheint sich gut über Plattformen hinweg zu arbeiten und minimiert die Menge an plattformspezifischen Code.

Ich würde verwenden Sie den folgenden Ansatz:

  1. eine ausführbare Datei erstellen, die das aktuelle Datum an stdout druckt (CMake fehlt diese Funktionalität)
  2. ein Ziel hinzufügen, die immer veraltet betrachtet
  3. Lassen Sie das Ziel ein anderes CMake Skript aufrufen
  4. Lassen Sie die aufgerufen CMake Skript eine Header-Datei
  5. erzeugen

Beispiel-Code für diese:

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

Dies führt zu einem Header „generated.h“, die auf jedem Build regeneriert wird. Wenn Sie im Wesentlichen als CMake vereinfacht nicht dieses Beispiel benötigen DATETIME- werden könnte fehlt diese Funktion und ein Programm muss gebaut werden, um die Funktionalität zu simulieren.

Ich würde denken, aber mehr als doppelt so hoch, bevor dies zu tun. Denken Sie daran, dass die Header-Datei jedes Mal make regeneriert wird ausgeführt, so dass Ihr Ziel ungültig in alle Zeiten. Sie werden nie haben eine Binärdatei, die up-to-date betrachtet wird.

funktionierts?

d=`perl -e"print qq(Whatever calculated at runtime);"`; g++ prog.cpp -o prog -DDATETIME=$$d
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top