Calling the resource compiler from a makefile - dll

I am trying to add some version number information to a dll being compiled using a makefile. I have created an .rc file that builds using rc.exe, however rc.exe builds the .res file in the location of the rc file. rather than the current directory. I need the .res file to build to the build location, so am using the /fo option. The problem is I would like to generate the same build file name that rc.exe creates, simply have it output to the current build folder.
On advice I have developed the following makefile section, but it complains of a missing ')':
{$(START_DIR)\..\common}.rc{$(START_DIR)\..\common}.res:
#cmd /C "echo ### Compiling $<"
$(RC) /fo .\$(patsubst %.rc, %.res, $(notdir $<)) $<
The intent is to take the file name from the path of the source ($<) and develop a new path substituting the current directory .\ for the source directory, the file name of the source, and the .rc extension for the compiled .res extension. This developed path is then put to the /fo option, and then the linker will find it in the current build path.
This is all borne out of the annoyance that rc.exe seems to behave differently to cl.exe, in that cl.exe will build all to the current directory, rc.exe will build to the source directory. If there were a simpler solution to this I could avoid this trouble with the makefile.
EDIT: Minimum complete example
\test
\test\test.rc
\test\output
\test\output\test.mk
\test\output\test.bat
test.rc
#include <windows.h>
//#include <winnt.h>
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL // VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS 0x1L // VS_FF_DEBUG|VS_FF_PRIVATEBUILD|VS_FF_PRERELEASE
#else
FILEFLAGS 0x0L // final version
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual
BEGIN
VALUE "Build", "August 2007\0"
VALUE "Comments", "Free for personal use only.\0"
VALUE "CompanyName", "Fake Company\0"
VALUE "Developer", "The Developer\0"
VALUE "FileDescription", "Application implementing something\0"
VALUE "FileVersion", "1.0.000\0"
VALUE "InternalName", "AppInternalName\0"
VALUE "LegalCopyright", "Copyright (C) 2007 Fake Company\0"
VALUE "LegalTrademarks", "All rights reserved.\0"
VALUE "OriginalFilename", "TheEXE.exe\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "The EXE\0"
VALUE "ProductVersion", "1.0.000\0"
VALUE "SpecialBuild", "\0"
VALUE "Support", "TheEXE at fake-domain.com\0"
VALUE "Users", "Unlimited.\0"
END // BLOCK "040904E4"
END // BLOCK "StringFileInfo"
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252 // 1252 = 0x04E4
END // BLOCK "VarFileInfo"
END'
test.mk:
{..\}.rc.res:
#cmd /C "echo ### Compiling $<"
$(RC) /fo .\$(patsubst %.rc,%.res,$(notdir $<)) $<
test.bat:
call "%VS100COMNTOOLS%..\..\VC\bin\vcvars64"
cd .
nmake -f test.mk
pause
From the test\output\ folder run the batch file.

Related

cmake, pass result of external program as preprocessor definitions

I'm new to cmake, so correct me if I've messed things up and this should be solved using something other than cmake.
I have main_program, that requires multiple other subprograms in form of bindata to be specified at build phase. Right now I build it by running
cmake -DBINDATA1="\xde\xad..." -DBINDATA2="\xbe\xef" -DBINDATA3="..."
and in code I use them as:
// main_program.cpp
int main() {
#ifdef BINDATA1
perform_action1(BINDATA1);
#endif
#ifdef BINDATA2
perform_action2(BINDATA2);
#endif
[...]
This is rather unclean method as any time I'm changing one of subprograms I have to generate bindata from it and pass it to cmake command.
What I would like to do, is have a project structure:
/
-> main_program
-> subprograms
-> subprogram1
-> subprogram2
-> subprogram3
and when I run cmake, I would like to
compile each of subprograms
generate shellcode from each of them, by running generate_bindata program on them
build main_program passing bindatas from step 2
and when I run cmake, I would like to
compile each of subprograms
generate shellcode from each of them, by running generate_shellcode program on them
build main_program passing shellcodes from step 2
Then let's do that. Let's first write a short script to generate a header:
#!/bin/sh
# ./custom_script.sh
# TODO: Find out proper quoting and add `"` is necessarily. Ie. details.
# Prefer to use actual real variables like `static const char *shellcode[3]`
# instead of raw macro defines.
cat > "$1" <<EOF
#define SHELLCODE1 $(cat "$2")
#define SHELLCODE2 $(cat "$3")
#define SHELLCODE3 $(cat "$4")
EOF
To be portable, write this script in cmake. This script will be run at build phase to generate the header needed for compilation. Then, "model dependencies" - find out what depends on what exactly. Then write it in cmake:
add_executable(subprogram1 sources.c...)
add_executable(subprogram2 sources.c...)
add_executable(subprogram3 sources.c...)
for(i IN ITEMS 1 2 3)
add_custom_target(
COMMENT Generate shellcode${i}.txt with the content of shellcode
# TODO: redirection in COMMAND should be removed, or the command
# should be wrapped in `sh -c ...`.
COMMAND $<TARGET_FILE:subprogram${i}> | generate_shellcode > ${CMAKE_CURRENT_BINARY_DIR}/shellcode${i}.txt
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/shellcode${i}.txt
DEPENDS $<TARGET_FILE:subprogram${i}> generate_shellcode
)
endfor()
add_custom_command(
COMMENT Generate shellcodes.h from shellcode1.txt shellcode2.txt and shellcode3.txt
COMMAND sh custom_script.sh
${CMAKE_CURRENT_BINARY_DIR}/shellcodes.h
${CMAKE_CURRENT_BINARY_DIR}/shellcode1.txt
${CMAKE_CURRENT_BINARY_DIR}/shellcode2.txt
${CMAKE_CURRENT_BINARY_DIR}/shellcode3.txt
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/shellcodes.h
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/shellcode1.txt
${CMAKE_CURRENT_BINARY_DIR}/shellcode2.txt
${CMAKE_CURRENT_BINARY_DIR}/shellcode3.txt
)
# Then compile the final executable
add_executable(main main.c ${CMAKE_CURRENT_BINARY_DIR}/shellcodes.h)
# Don't forget to add includes!
target_include_directories(main PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
# or you may add dependency to a single file instead of target
# Like below only to a single shellcodeswrapper.c file only
# This should help build parallelization.
set_source_files_properties(main.c OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/shellcodes.h)
# Or you may add a target for shelcodes header file and depend on it
add_custom_target(shellcodes DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/shellcodes.h)
add_executable(main main.c)
target_include_directories(main PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(main shellcodes)
Then your main file:
#include <shellcodes.h> // compiler will find it in BINARY_DIR
int main() {
perform_action1(SHELLCODE1);
perform_action2(SHELLCODE2);
}
So that all your source files are not recompiled each time, I suggest to write a wrapper:
// shellcodewrapper.c
#include <shellcodes.h>
// preserve memory by not duplicating code in each TU
static const char shellcode1[] = SHELLCODE1;
// only this file will be recompiled when SHELLCODE changes
const char *get_shellcode1(void) {
return shellcode1;
}
// shellcodewrapper.h
const char *get_shellcode1(void);
// main.c
#include <shellcodewrapper.h>
int main() {
perform_action1(get_shellcode1());
perform_action2(get_shellcode2());
}
That way when you change the "SHELLCODE" generators, only shellcodewrapper.c will be compiled, resulting in super fast compilation times.
Note how dependency is transferred and how it works - I used files inside BINARY_DIR to transfer result from one command to another, then these files track what was changed and transfer dependency below in the chain. Track dependencies in DEPENDS and OUTPUT in add_custom_command and cmake will properly compile in proper order.

CMake: How can I compile defines and flags as string constants into my C(++) program?

I'd like my C or C++ program that is built via CMake to be able to print (or otherwise make use of) the macro definitions and (other) C/C++ flags it was compiled with. So I want CMake to generate/configure a header or source file that defines respective strings constants and that is then built as part of/into my program.
CMake features several commands (like file() or execute_process()) that would be executed when (respectively before) the build system is generated and thus would allow me to write such a source file, but I'm having trouble with getting the effective macro definitions and flags used for my target. E.g. there seem to be COMPILE_DEFINITIONS for the directory, the target, and for the configuration. Is there a way to get the macro definitions/C(++) flags that are effectively used for building my target? And how do I best write them into a source file?
I've noticed, when using the Makefiles generator apparently a file "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/MyTarget.dir/flags.make" is created, which seems to contain pretty much what I'm looking for. So if there's no other way, I can probably make use of that file, but obviously that won't work for other generators and it comes with its own challenges (the file is generated after execute_process()).
The approach I finally went with sets the CXX_COMPILER_LAUNCHER property to use a compiler wrapper script that injects the actual compiler command line into a source file. Since I have multiple libraries/executables to which I want to add the respective information, I use a CMake function that adds a source file containing the info to the target.
function(create_module_build_info _target _module _module_include_dir)
# generate BuildInfo.h and BuildInfo.cpp
set (BUILD_MODULE ${_module})
set (BUILD_MODULE_INCLUDE_DIR ${_module_include_dir})
configure_file(${CMAKE_SOURCE_DIR}/BuildInfo.h.in
${CMAKE_BINARY_DIR}/include/${_module_include_dir}/BuildInfo.h
#ONLY)
configure_file(${CMAKE_SOURCE_DIR}/BuildInfo.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/BuildInfo.cpp
#ONLY)
# Set our wrapper script as a compiler launcher for the target. For
# BuildInfo.cpp we want to inject the build info.
get_property(_launcher TARGET ${_target} PROPERTY CXX_COMPILER_LAUNCHER)
set_property(TARGET ${_target} PROPERTY CXX_COMPILER_LAUNCHER
${CMAKE_SOURCE_DIR}/build_info_compiler_wrapper.sh ${_launcher})
get_property(_compile_flags SOURCE BuildInfo.cpp PROPERTY COMPILE_FLAGS)
set_property(SOURCE BuildInfo.cpp PROPERTY COMPILE_FLAGS
"${_compile_flags} -D_BUILD_INFO=${CMAKE_CURRENT_BINARY_DIR}/BuildInfo_generated.cpp,${_module}")
# add BuildInfo.cpp to target
target_sources(${_target} PRIVATE BuildInfo.cpp)
endfunction()
The function can simply be called after defining the target. Parameters are the target, a name that is used as a prefix of the constant name to be generated, and a name that is part of the path of the header file to be generated. The compiler flag -D_BUILD_INFO=... is only added to the generated source file and it will be used by the wrapper script as an indicator that the constant definition should be added to that source file. All other compiler lines are just invoked as is by the script.
The template source file "BuildInfo.cpp.in":
#include "#BUILD_MODULE_INCLUDE_DIR#/BuildInfo.h"
The template header file "BuildInfo.h.in":
#pragma once
#include <string>
extern const std::string #BUILD_MODULE#_COMPILER_COMMAND_LINE;
The compiler wrapper script "build_info_compiler_wrapper.sh":
#!/usr/bin/env bash
set -e
function createBuildInfoTempFile()
{
local source="$1"
local target="$2"
local prefix="$3"
local commandLine="$4"
cp "$source" "$target"
cat >> "$target" <<EOF
const std::string ${prefix}_COMPILER_COMMAND_LINE = "$commandLine";
EOF
}
# Process script arguments. We copy them to array variable args. If we find an
# argument "-D_BUILD_INFO=*", we remove it and will inject the build info
# variable definition into (a copy of) the input file.
generateBuildInfo=false
buildInfoTempFile=
buildInfoVariablePrefix=
args=()
while [ $# -ge 1 ]; do
case "$1" in
-D_BUILD_INFO=*)
if [[ ! "$1" =~ -D_BUILD_INFO=([^,]+),(.+) ]]; then
echo "error: failed to get arguments for build info generation" >&2
exit 1
fi
generateBuildInfo=true
buildInfoTempFile="${BASH_REMATCH[1]}"
buildInfoVariablePrefix="${BASH_REMATCH[2]}"
shift
continue
;;
esac
args+=("$1")
shift
done
if $generateBuildInfo; then
# We expect the last argument to be the source file. Check!
case "${args[-1]}" in
*.c|*.cxx|*.cpp|*.cc)
createBuildInfoTempFile "${args[-1]}" "$buildInfoTempFile" "$buildInfoVariablePrefix" "${args[*]}"
args[-1]="$buildInfoTempFile"
;;
*)
echo "error: Failed to find source file in compiler arguments for build info generation feature." >&2
exit 1
;;
esac
fi
"${args[#]}"
Obviously the script can be made smarter. E.g. instead of assuming it is the last argument it could find the actual index of the input source file. It could also process the command line to separate preprocessor definitions, include paths, and other flags.
Note that "-D_BUILD_INFO=..." argument is used instead of some parameter that the compiler wouldn't know (e.g. "--generate-build-info"), so that IDEs won't run into issues when passing the arguments directly to the compiler for whatever purposes.

Using an interface library with check_c_source_runs() or try_run()

Use case: I'm trying to compile a test program that probes for a list of TrueType(tm) fonts using SDL2_ttf (with SDL2, Freetype, PNG and Zlib). The SDL2_ttf::SDL2_ttf interface library exists and links successfully with target executables. My problem is how to get check_c_source_runs() to pick up the definitions, include directories and libraries. I'd rather not have to manually extract everything from properties, as in the following code fragment:
include(CheckCSourceRuns)
get_property(defs TARGET SDL2_ttf::SDL2_ttf PROPERTY INTERFACE_COMPILE_DEFINITIONS)
get_property(incs TARGET SDL2_ttf::SDL2_ttf PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
get_property(libs TARGET SDL2_ttf::SDL2_ttf PROPERTY INTERFACE_LINK_LIBRARIES)
## Transform the definitions with "-D"
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.12")
list(TRANSFORM defs PREPEND "-D")
list(TRANSFORM incs PREPEND "-I")
else ()
## Code that does what list(TRANSFORM...) does in less capable CMake
## versions.
endif ()
set(CMAKE_REQUIRED_DEFINITIONS ${defs})
set(CMAKE_REQUIRED_INCLUDES ${incs})
set(CMAKE_REQUIRED_LIBRARIES ${libs})
check_c_source_runs("
#include <stdint.h>
#include <SDL.h>
#include <SDL_ttf.h>
int main(int argc, char *argv[])
{
const char *fonts[] = {\"DejaVuSans.ttf\", \"LucidaSansRegular.ttf\", \"FreeSans.ttf\", \"AppleGothic.ttf\", \"tahoma.ttf\"};
size_t i, cnt = 0;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
for (i = 0; i < sizeof(fonts)/sizeof(fonts[0]); ++i) {
TTF_Font *ttf = TTF_OpenFont(fonts[i], 10);
if (ttf != NULL) {
fputs(fonts[i], stderr);
if (cnt++ > 0) {
fputc(';', stderr);
}
TTF_CloseFont(ttf);
}
}
TTF_Quit();
SDL_Quit();
return 0;
}" ttfprobe_run)
Link libraries are hairy, since there are interface libraries referenced from within SDL2_ttf::SDL2_ttf, e.g. FreeType::FreeType.
Suggestions?
Functions try_compile and try_run and everything which is based on them (e.g. check_c_source_runs) are actually build some other CMake project. Because you cannot pass targets to the CMake project, you have two ways:
Extract all needed target's properties to the variables and pass them to the newly generated project. As you already do.
Write CMakeLists.txt for other project manually, and use calls to find_package and other package-discovery functions in it.
E.g., you may write CMakeLists.txt for other project like that:
# Source file is in SOURCE_FILE parameter,
# resulted executable is copied into the file pointed by EXE_FILE parameter.
cmake_minimum_required(...)
project(test_project)
# This will create 'SDL2_ttf::SDL2_ttf' target
find_package(SDL2_ttf REQUIRED)
add_executable(test_exe ${SOURCE_FILE})
target_link_libraries(test_exe SDL2_ttf::SDL2_ttf)
add_custom_command(OUTPUT ${EXE_FILE}
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:test_exe> ${EXE_FILE}
DEPENDS $<TARGET_FILE:test_exe>
)
add_custom_target(copy_exe ALL DEPENDS ${EXE_FILE})
The main challenge is to pass as many variables to the other project as needed for it to be built in the same "environment" as the main project.
Example below handles only variables which could affect on find_package(SDL2_ttf) call:
# Main project
# Somewhere you have this call too.
find_package(SDL2_ttf REQUIRED)
# List of arguments for the subproject
set(SUBPROJECT_ARGS
# This affects on searching for possible `FindSDL2_ttf.cmake` script
-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}
# This affects on searching for `find_*` calls in find script.
-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
)
if (SDL2_ttf_DIR)
# This is a directory with `SDL2_ttfConfig.cmake` script
list(APPEND SUBPROJECT_ARGS -DSDL2_ttf_DIR=${SDL2_ttf_DIR})
endif()
# build subproject
try_compile(TTF_TEST_RESULT # Variable which will contain result of building the subproject
${CMAKE_CURRENT_BINARY_DIR}/ttf_test # Build directory for the subproject
<src-dir> # Source directory for the subproject, where its `CMakeLists.txt` resides.
test_project # Project name of the subproject
CMAKE_FLAGS
-DSOURCE_FILE=<src-file> # Source file
-DEXE_FILE=<exe-file> # Path to the resulted executable file
${SUBPROJECT_ARGS} # The rest of arguments for subproject
OUTPUT_VAR TTF_TEST_OUTPUT # Variable which will contain output of the build process
)
if (TTF_TEST_RESULT)
# Subproject has been built successfully, now we can try to execute resulted file
...
endif()
Tricky? Yes. But this is how CMake works...

CMake : add executable with unknown genererated source files

I have a tool that generates a set source files whose name I am not able to know beforehand.
How to write a proper CMakeLists.txt script for scenario? This question has been asked before here CMake Compiling Generated Files. But it does not have a proper solution.
For instance, in the first answer (https://stackoverflow.com/a/8748478/2912478), OP can predict which files will generated based on the input .idl files. The second answer (https://stackoverflow.com/a/39258996/2912478) shows three different ways to solve but I really couldn't get his solution working.
Test case
I prepared a simple test case. Suppose I have this static file where the main resides (main.cpp).
# main.cpp
void foo(void);
int main() {
foo();
return 0;
}
Currently, I am using this CMakeLists.txt. The custom command generates the source file under src.
# CMakeLists.txt
add_executable(a.out main.cpp)
add_custom_command(
OUTPUT mylib.cpp
COMMAND ${CMAKE_SOURCE_DIR}/genf.sh ${CMAKE_SOURCE_DIR}/src
DEPENDS ${CMAKE_SOURCE_DIR}/genf.sh
)
add_custom_target(GenFile DEPENDS mylib.cpp)
add_dependencies(a.out GenFile)
Here is the hypothetical code generator genf.sh. I use a random number to mimic the fact that we do NOT know which files the generator will generate.
#!/bin/bash
rm -rf $1/*
fname=$(echo $((1 + RANDOM % 100)))
echo "Generating src$fname.cpp"
echo "void foo(void) {}" > $1/src$fname.cpp
Attempt 1
I tried to use GLOB to find all files generated. So I put the following lines at the end of my CMakeLists.txt. This doesn't work because at the moment of running cmake .. there is no files under src. So this solution never links the generated source files.
file(GLOB GeneratedSourceFiles ${CMAKE_SOURCE_DIR}/src/*.cpp)
target_sources(a.out PUBLIC ${GeneratedSourceFiles})

cmake - preset settings for entries from ini file

I have a project that uses some third party libraries. So each time I setup this project with CMake, I have to set each entry (path of the third party library) on the GUI of CMake. I improve this by making CMake script guess the path by this script (learn this technique from OGRE):
# Guess the paths.
set( OGRE_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/Ogre" CACHE STRING "Path to OGRE source code (see http://www.ogre3d.org/tikiwiki/tiki-index.php?page=CMake+Quick+Start+Guide)" )
So each time I setup with CMake, it will automatic fill the entry OGRE_SOURCE. But that doesn't enough. If the Ogre source is not in the path
"${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/Ogre"
, then I have to open and edit the CMake script or I have to edit the entry on the GUI of CMake. I find that pretty inconvenient, especially when you link to a lot of third party libraries.
So I want to use another technique: preset settings for entries from file - CMake reads the presets from file PresetEntries.txt (that I make) and apply the these presets on the entries (It's a lot quicker to edit the path in text file than on the GUI of CMake).
Here my idea about this preset file: PresetEntries.txt
OGRE_SOURCE=E:/Source/ogre
I found that CMake can read a text file, but if I use this, I have to do string manipulations.
CMake has the file CMakeCache.txt to save the settings on the CMake GUI, but I want it to be simple: it should only has the preset settings that need to be pre-set.
So I wonder if CMake support this preset settings for entries from file.
Edit:
So I read this question and see that CMake can set config from file, but this require to fire cmake with the -C mysettings.cmake, but I wanna it to be automatically with CMake GUI - just edit the file and hit generate button in CMake GUI. So I wanna make this question more specific:
In my CMakeLists.txt should have script like this:
# Guess the paths.
#I wanna have this function from C++
#https://msdn.microsoft.com/en-us/library/windows/desktop/ms724353%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
GetPrivateProfileString("OGRE", #lpAppName
"OGRE_SOURCE", #lpKeyName
"${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/Ogre", #lpDefault
OGRE_SOURCE_VAR,#lpReturnedString
MAX_PATH, #nSize, may be can reduce this variable
"LibPath.ini") #lpFileName
set( OGRE_SOURCE "${OGRE_SOURCE_VAR}" CACHE STRING "Path to OGRE source code" )
In the file LibPath.ini
[OGRE]
OGRE_SOURCE = "E:/Source/ogre"
So the user can choose to either use the ini file or not.
I don't know if there any way I can use a function that similar to function GetPrivateProfileString (of C++) in CMake.
Thanks for reading
The external libraries should be included by one of the following commands
find_package(ttnlib REQUIRED HINTS /usr/local/lib/cmake)
include_directories(${ttnlib_INCLUDE_DIR})
set(EXTRA_LIBS ${EXTRA_LIBS} ${TTNLIB_LIBRARY})
or
find_library(MY_EXTERNAL_LIB name COOLSTUFF libCOOLSTUFF libCOOLSTUF.so hints /usr/local/lib)
The search for the external packages and libraries should only be necessary for the first run of cmake.
I can't find the function to read the ini file, so what I can do is create a simple function that read simple txt file for myself.
I declare the function in 1 file for other file use it
"\CMake\Dependencies\CommonFunc.cmake"
#------------Define function Read file------------
macro( readSettingFile KEY DEFAULT_RESULT STRING_RESULT_OUT)
unset(STRING_RESULT)
# Read the file
file( READ "${CMAKE_SOURCE_DIR}/LibPath.txt" LIB_PATH_STR )
# Set the variable "Esc" to the ASCII value 27 - basically something
# which is unlikely to conflict with anything in the file contents.
string(ASCII 27 Esc)
# Turn the contents into a list of strings, each ending with an Esc.
# This allows us to preserve blank lines in the file since CMake
# automatically prunes empty list items during a foreach loop.
string(REGEX REPLACE "\n" "${Esc};" LIB_PATH_LINES "${LIB_PATH_STR}")
foreach(LINE ${LIB_PATH_LINES})
if("${LINE}" MATCHES "${KEY}")
#remove the key, leave the content untouch
string(REPLACE "${KEY}" "" STRING_RESULT ${LINE})
# Swap the appended Esc character back out in favour of a line feed
string(REGEX REPLACE "${Esc}" "" STRING_RESULT ${STRING_RESULT})
endif()
endforeach()
if("${STRING_RESULT}" STREQUAL "")
set( STRING_RESULT ${DEFAULT_RESULT} )
endif()
#message( STATIC "---GTA Sa-----" "[${STRING_RESULT}]" )
endmacro()
(I need the help from this answer to write this function :p)
Here is how I use
For example: "\CMake\Dependencies\Ogre.cmake"
#include common functions
include( CMake/Dependencies/CommonFunc.cmake )
#---------------Guess the paths.----------------------
#----Set OGRE_SOURCE
readSettingFile( "OGRE_SOURCE="
"E:/Source/ogre"
STRING_RESULT
)
set( OGRE_SOURCE "${STRING_RESULT}" CACHE STRING "Path to OGRE Source" )
#----Set OGRE_BINARIES
readSettingFile( "OGRE_BINARIES="
"E:/Source/_build/ogre"
STRING_RESULT
)
set( OGRE_BINARIES "${STRING_RESULT}" CACHE STRING "Path to OGRE's build folder generated by CMake" )
Here is the setting file
"\LibPath.txt"
OGRE_SOURCE=E:/Source/ogre
OGRE_BINARIES=E:/Source/_build/ogre