كيفية تشغيل أمر في وقت الترجمة في Makefile الناتجة عن CMake?

StackOverflow https://stackoverflow.com/questions/1438535

سؤال

أود أن تمر بعض الخيارات إلى مترجم.الخيار يجب أن تكون محسوبة في وقت الترجمة - في كل مرة عندما 'جعل' هو الاحتجاج ليس عندما 'cmake' ، لذلك execute_process الأمر لا قطع عليه.(أليس كذلك؟)

فعلى سبيل المثال تمرير موعد g++ compiler مثل هذا:

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

ولكن مع التاريخ والوقت محسوب في وقت الترجمة.

أي فكرة عن كيفية القيام بذلك في CMake?

فضله تحرير:

على الأقل hackish الحل لن يكون مقبولا.

يرجى ملاحظة أن كنت تريد أن تكون قادرة على exectue التعسفي الأمر في وقت الترجمة ، ليس فقط 'تاريخ'.

تحرير 2:

يجب أن تعمل على لينكس, ويندوز (مقابل) ، مينغو, Cygwin و OS X.لا يمكنك أن تفترض Ruby, Perl أو Python كما هي غير القياسية على نظام التشغيل ويندوز.يمكنك أن تفترض دفعة, ولكن أعتقد أنه لا فائدة.

الهدف هو إجبار cmake لتوليد Makefile (في حالة لينكس) أنه عندما جعل تنفيذه سيتم القيام بهذه المهمة.

خلق العرف *.ساعة الملف على ما يرام ، لكن يجب أن تكون بمبادرة من Makefile (أو ما يعادلها في نظام التشغيل الأخرى) عن طريق جعل.إنشاء *.ح لا يجب أن (أن لا يكون) استخدام cmake.

هل كانت مفيدة؟

المحلول

كنت تاركة بعض المعلومات ، مثل منصات عليك لتشغيل هذا و إذا كان هناك أي أدوات إضافية يمكنك استخدامها.إذا يمكنك استخدام Ruby, Perl, الثعبان, تصبح الأمور أبسط من ذلك بكثير.سوف افترض أنك تريد تشغيل Unix وwindows pqlatform ، أنه لا توجد الأدوات الإضافية المتاحة.

إذا كنت تريد الإخراج من الأمر في المعالج الرمز ، أسهل طريقة لإنشاء ملف الرأس بدلا من تافه حولها مع معلمات سطر الأوامر.تذكر أن 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)

ملف "العرف.ح" تم إنشاؤه في وقت الترجمة من قبل قيادة "cmake -P مخصص.cmake".مخصص.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 ، ومن ثم يكتب إلى العرف.ح.لاحظ أن هذا سوف فقط العمل إذا كان الأمر نواتج خط واحد.(إذا كنت بحاجة إلى متعدد الإخراج ، عليك أن تكتب أكثر تعقيدا مخصص.cmake ، اعتمادا على كيف تريد متعدد البيانات في البرنامج.)

البرنامج الرئيسي يبدو مثل هذا:

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

إذا كنت فعلا تريد لحساب خيارات برنامج التحويل البرمجي في وقت الترجمة ، تصبح الأمور أكثر تعقيدا من ذلك بكثير.بالنسبة بورن-قذيفة مولدات يمكنك فقط أدخل الأوامر داخل backticks.إذا كنت تغضب حين معرفة نقلا عن نقل كافة المنطق من القيادة داخل قذيفة النصي بحيث تحتاج فقط إلى وضع mycommand.sh في add_definitions():

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

ويندوز الملف الدفعي على أساس مولدات الأمور كثيرا tricker, وأنا لا يكون حلا جيدا.المشكلة هي أن PRE_BUILD الأوامر لا تنفذ كجزء من نفس الملف الدفعي الفعلية مترجم الاحتجاج (دراسة BuildLog.htm لمزيد من التفاصيل) ، الفكرة الأولية لم تنجح (توليد مخصص.بات في PRE_BUILD الخطوة ومن ثم القيام "دعوة مخصصة.الخفافيش" على ذلك للحصول على مجموعة متغير والتي يمكن أن تكون في وقت لاحق المشار إليها في سطر الأوامر برنامج التحويل البرمجي).إذا كان هناك ما يعادل backticks في الملفات الدفعية, هذا من شأنه أن يحل المشكلة.

نأمل أن يكون هذا يعطي بعض الأفكار و نقطة انطلاق.

(الآن لا مفر منها مكافحة السؤال:ما أنت حقا تحاول أن تفعل؟)

تحرير:لست متأكدا لماذا أنت لا تريد أن تدع CMake استخدامها لتوليد رأس الملف.باستخدام ${CMAKE_COMMAND} سوف توسع إلى CMake المستخدمة لتوليد Makefiles/.vcproj-ملفات و منذ CMake لا دعم المحمولة Makefiles/.vcproj الملفات سوف تحتاج إلى إعادة تشغيل CMake على الأجهزة المستهدفة.

CMake أيضا لديه مجموعة من المرافق الأوامر (Run "cmake -E" عن قائمة) هذا صريح العقل.يمكنك على سبيل المثال لا

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

نسخ التنسيق file1.ح إلى file2.ح.

على أي حال, إذا كنت لا تريد أن تولد رأس الملفات باستخدام CMake, سوف تحتاج إلى استدعاء منفصلة .bat/.sh مخطوطات لتوليد ملف الرأس ، أو القيام بذلك باستخدام الصدى:

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

ضبط نقلا حسب الحاجة.

نصائح أخرى

الحل أعلاه (باستخدام منفصل CMake الملف النصي إلى إنشاء ملف رأس) يبدو مرنة جدا ولكن معقدة بعض الشيء عن ما يجري في المثال.

البديل هو وضع COMPILE_DEFINITIONS الملكية على أي فرد الملف المصدر أو الهدف في هذه الحالة المحددة مسبقا المعالج المتغيرات سوف تكون مصدر الملف أو الملفات في الهدف يتم تجميعها.

على COMPILE_DEFINITIONS خصائص لها شكل مختلف عن تلك المستخدمة في add_definitions القيادة لديها ميزة أن كنت لا داعي للقلق حول "د" أو "\د" بناء الجملة وأنها تعمل عبر منصة.

رمز المثال

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

السطر الأول يدير الأمر shell svnversion و يضع النتيجة في متغير SVN_REV.على string(STRIP ...) الأمر بحاجة إلى إزالة زائدة حرف السطر الجديد من الإخراج.

ملاحظة هذا هو افتراض أن الأمر يتم تشغيل هو عبر منصة.إن لم يكن قد تحتاج إلى بدائل منصات مختلفة.على سبيل المثال يمكنني استخدام cygwin تنفيذ Unix date الأوامر،:

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)

عن تاريخ الأوامر ، حيث win_date.bat هو bat أن مخرجات التاريخ في الشكل المطلوب.

اثنين من قبل المعالج المتغيرات غير متوفرة في الملف ./VersionInfo.cpp ولكن لم تحدد في أي ملفات أخرى.ثم يمكن أن يكون

-- VersionInfo.cpp --

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

ويبدو أن تعمل بشكل جيد عبر منصات ويقلل كمية من منصة رمز معين.

وأود أن استخدام النهج التالي:

  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)

--- توليد.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)

--- توليد.ح.في ---

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

هذه النتائج في رأس "ولدت.ح" الذي هو مجدد في كل بناء.إذا كنت لا تحتاج إلى التاريخ والوقت هذا المثال يمكن أن تكون مبسطة إلى حد كبير كما CMake يفتقر إلى هذه الميزة ، يجب أن يكون البرنامج مبني لمحاكاة وظائف.

أود أن أعتقد أكثر من مرتين قبل القيام بذلك.تذكر أن رأس الملف سيتم تجديدها في كل مرة جعل تشغيل صنع الهدف الخاص بك غير صالحة في كل مرات.سوف أبدا وقد الثنائية التي تعتبر ما يصل إلى التاريخ.

يعمل هذا ؟

d=`perl -e"print qq(Whatever calculated at runtime);"`; g++ prog.cpp -o prog -DDATETIME=$$d
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top