c++ - Cmake Regenerate on variable change -


y part:

i've got cmake macro runs external program , creates project specific variables. i'd have cmake run script on every build, check if variables have changed, , iff have (to prevent full project rebuild when has not), regenerate configure_file header...i'm not sure how though. (add custom target rebuilds header file every time , can't call macros, same add custom command).

x part:

so i've written following script pulling hg version information use in c++ project:

macro (readprojectrevisionstatus) exec_program(hg ${project_source_dir} args paths output_variable ${project_name}_hgpaths) message(status "${project_name}_hgpaths=${${project_name}_hgpaths}}") if (not(${project_name}_hgpaths strequal ""))  string(replace "\n" ";" ${project_name}_hgpaths ${${project_name}_hgpaths})  foreach(hgpath ${${project_name}_hgpaths}) string(substring "${hgpath}" 0 10 hgpathstart) if (hgpathstart matches "default = ") string(length "${hgpath}" hgpathlength) math(expr hgsublen "${hgpathlength}-10") string(substring "${hgpath}" 10 ${hgsublen} ${project_name}_hgremotedir) endif() endforeach()  endif()  if (not ${project_name}_hgremotedir) message(warning "no remote repository set. use current direcoty build number, value may inaccurate.") set(${project_name}_hgremotedir ${project_source_dir}) else() exec_program(hg ${${project_name}_hgremotedir} args status return_value hgremotestatusvalue output_variable nul) if (not hgremotestatusvalue equal 0) message(warning "cannot connect remote repository @ ${${project_name}_hgremotedir}. use current direcoty build number, value may inaccurate.") set(${project_name}_hgremotedir ${project_source_dir}) endif() endif()  #identify changeset exec_program(hg ${project_source_dir} args "id" "-i" output_variable output_variable ${project_name}_hghashcode)  if (${project_name}_hghashcode matches ".*\\+") message(status "node dirty. generate temporary version number...") set (${project_name}_hgdirty 1) string(length ${${project_name}_hghashcode} hghashlen) math(expr hghashlen "${hghashlen}-1") string(substring ${${project_name}_hghashcode} 0 ${hghashlen} ${project_name}_hghashcode) endif() #check if remote repository contains changeset exec_program(hg ${${project_name}_hgremotedir} args "log" "-r" "${${project_name}_hghashcode}" return_value hgremotehaschangeset output_variable nul) if (not hgremotehaschangeset equal 0) message(warning "remote repository ${${project_name}_hgremotedir} not have changeset ${${project_name}_hghashcode}. use current direcoty build number, value may inaccurate.") set(${project_name}_hgremotedir ${project_source_dir}) endif()  exec_program(hg ${${project_name}_hgremotedir} args "log" "-r" ${${project_name}_hghashcode} "--template" "{latesttag}" output_variable ${project_name}_hgmajorminorversion)  message(status "${project_name}_hgmajorminorversion=${${project_name}_hgmajorminorversion}")  exec_program(hg ${${project_name}_hgremotedir}  args "log" "-r" ${${project_name}_hghashcode} "--template" "{latesttagdistance}"  output_variable ${project_name}_hgbuildnumber)  if (${project_name}_hgdirty) math(expr ${project_name}_hgbuildnumber "${${project_name}_hgbuildnumber}+1") set(${project_name}_hghashcode "${${project_name}_hghashcode}+") endif()  message(status "version=${${project_name}_hgmajorminorversion}.${${project_name}_hgbuildnumber}.${${project_name}_hghashcode}") endmacro() 

and call this.

readprojectrevisionstatus() configure_file(${cmake_current_source_dir}/main.h.in ${cmake_current_binary_dir}/main.h) 

where main.h.in is:

#ifndef main_h #define main_h #include <string>  const std::string ${project_name}_hgmajorminorversion = "${${project_name}_hgmajorminorversion}"; const std::string ${project_name}_hgbuildnumber = "${${project_name}_hgbuildnumber}"; const std::string ${project_name}_hghashcode = "${${project_name}_hghashcode}";  const std::string ${project_name}_hg_short_version =      ${project_name}_hgmajorminorversion+"."+     ${project_name}_hgbuildnumber;  const std::string ${project_name}_hg_version =      ${project_name}_hg_short_version + "." +     ${project_name}_hghashcode;  #endif 

what i'd run macro on every build command (i can use add_custom_target , set variables instead of reading them project), want regenerate main.h if variables have changed (to prevent unnecessary recompilation).

edit: working solution

made hgversion.cmake

cmake_minimum_required (version 2.8)  macro (readprojectrevisionstatus) message(status project_source_dir=${project_source_dir})  exec_program(hg ${project_source_dir} args paths output_variable ${project_name}_hgpaths) message(status "${project_name}_hgpaths=${${project_name}_hgpaths}}") if (not(${project_name}_hgpaths strequal ""))  string(replace "\n" ";" ${project_name}_hgpaths ${${project_name}_hgpaths})  foreach(hgpath ${${project_name}_hgpaths}) string(substring "${hgpath}" 0 10 hgpathstart) if (hgpathstart matches "default = ") string(length "${hgpath}" hgpathlength) math(expr hgsublen "${hgpathlength}-10") string(substring "${hgpath}" 10 ${hgsublen} ${project_name}_hgremotedir) endif() endforeach()  endif()  if (not ${project_name}_hgremotedir) message(warning "no remote repository set. use current direcoty build number, value may inaccurate.") set(${project_name}_hgremotedir ${project_source_dir}) else() exec_program(hg ${${project_name}_hgremotedir} args status return_value hgremotestatusvalue output_variable nul) if (not hgremotestatusvalue equal 0) message(warning "cannot connect remote repository @ ${${project_name}_hgremotedir}. use current direcoty build number, value may inaccurate.") set(${project_name}_hgremotedir ${project_source_dir}) endif() endif()  #identify changeset exec_program(hg ${project_source_dir} args "id" "-i" output_variable output_variable ${project_name}_hghashcode)  if (${project_name}_hghashcode matches ".*\\+") message(status "node dirty. generate temporary version number...") set (${project_name}_hgdirty 1) string(length ${${project_name}_hghashcode} hghashlen) math(expr hghashlen "${hghashlen}-1") string(substring ${${project_name}_hghashcode} 0 ${hghashlen} ${project_name}_hghashcode) endif() #check if remote repository contains changeset exec_program(hg ${${project_name}_hgremotedir} args "log" "-r" "${${project_name}_hghashcode}" return_value hgremotehaschangeset output_variable nul) if (not hgremotehaschangeset equal 0) message(warning "remote repository ${${project_name}_hgremotedir} not have changeset ${${project_name}_hghashcode}. use current direcoty build number, value may inaccurate.") set(${project_name}_hgremotedir ${project_source_dir}) endif()  exec_program(hg ${${project_name}_hgremotedir} args "log" "-r" ${${project_name}_hghashcode} "--template" "{latesttag}" output_variable ${project_name}_hgmajorminorversion)  message(status "${project_name}_hgmajorminorversion=${${project_name}_hgmajorminorversion}")  exec_program(hg ${${project_name}_hgremotedir}  args "log" "-r" ${${project_name}_hghashcode} "--template" "{latesttagdistance}"  output_variable ${project_name}_hgbuildnumber)  if (${project_name}_hgdirty) math(expr ${project_name}_hgbuildnumber "${${project_name}_hgbuildnumber}+1") set(${project_name}_hghashcode "${${project_name}_hghashcode}+") endif()  message(status "version=${${project_name}_hgmajorminorversion}.${${project_name}_hgbuildnumber}.${${project_name}_hghashcode}") endmacro() message(status "getting hg version") readprojectrevisionstatus() configure_file(${project_source_dir}/main.h.in ${project_binary_dir}/main.h) 

in main cmake file

add_custom_target( ${project_name}_hg_version_target  depends ${cmake_current_source_dir}/main.h.in  command ${cmake_command}  args -dproject_source_dir=${project_source_dir}  -dproject_name=${project_name}  -dproject_binary_dir=${project_binary_dir}  -p "${cmake_current_source_dir}/hgversion.cmake") 

and

add_dependencies(${project_name} ${project_name}_hg_version_target)

works seems...real messy. got better?

if during build process determines contents of file generated, cannot generate file configure_file, because configure_file operates during configuration phase , not @ build time. design choice cmake.

in case have use add_custom_command , add_custom_target generate file during build process, found out already.

for proposed solution there might chance simplify bit. generating c/c++ header file, cmake internal parser should able automatically discover of usual source code files depend on main.h. should sufficient provide custom command add_custom_command, declares output main.h file generate. cmake should call command automatically once tries build target 1 of c/c++ files depends on it. not need custom target , manually declared dependency.


Comments

Popular posts from this blog

plot - Remove Objects from Legend When You Have Also Used Fit, Matlab -

java - Why does my date parsing return a weird date? -

Need help in packaging app using TideSDK on Windows -