CMAKE: Conditionally Initializing a Cache Variable dependant on the Generator Type - build-process

I currently have a basic Cmake file that sets certain library directories. I would like to conditionally intitalise based on the target generator -- in my case the generator determines which base directories to use (64-bit visual studio generator vs a regular visual studio generator).
My CMakeLists file looks as follows:
PROJECT(STAT_AUTH)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(BOOST_DIR "c:\\dev_32\\Boost" CACHE PATH "The Boost Directory Path")
SET(PROTOBUF_DIR "c:\\dev_32\\Protobuf" CACHE PATH "The Protobuf directory Path")
SET(OPENSSL_DIR "c:\\dev_32\\OpenSSL" CACHE PATH "The OpenSSL Directory Path"
How do I conditionally initialise the variables so they get set to 64-bit versions when I generate to 64-bit generators. The default setting should show up in the Cmake Gui / ccmake before I choose the "generate" option.

Try:
if(CMAKE_SIZEOF_VOID_P MATCHES 4)
SET(BOOST_DIR "c:\\dev_32\\Boost" CACHE PATH "The Boost Directory Path")
SET(PROTOBUF_DIR "c:\\dev_32\\Protobuf" CACHE PATH "The Protobuf directory Path")
SET(OPENSSL_DIR "c:\\dev_32\\OpenSSL" CACHE PATH "The OpenSSL Directory Path"
else()
SET(BOOST_DIR "c:\\dev_64\\Boost" CACHE PATH "The Boost Directory Path")
SET(PROTOBUF_DIR "c:\\dev_64\\Protobuf" CACHE PATH "The Protobuf directory Path")
SET(OPENSSL_DIR "c:\\dev_64\\OpenSSL" CACHE PATH "The OpenSSL Directory Path"
endif()

For Windows the following syntax is apt. CMAKE_CL_64 defines the x86_64 compiler specifically.
if(MSVC)
if(CMAKE_CL_64)
SET(BOOST_DIR "c:\\dev_64\\Boost" CACHE PATH "The Boost Directory Path")
SET(PROTOBUF_DIR "c:\\dev_64\\Protobuf" CACHE PATH "The Protobuf directory Path")
SET(OPENSSL_DIR "c:\\dev_64\\OpenSSL" CACHE PATH "The OpenSSL Directory Path")
SET(DEPLOY_DIR "c:\\root_64" CACHE PATH "The Deploy Path for the components built" )
else()
SET(BOOST_DIR "c:\\dev_32\\Boost" CACHE PATH "The Boost Directory Path")
SET(PROTOBUF_DIR "c:\\dev_32\\Protobuf" CACHE PATH "The Protobuf directory Path")
SET(OPENSSL_DIR "c:\\dev_32\\OpenSSL" CACHE PATH "The OpenSSL Directory Path")
SET(DEPLOY_DIR "c:\\root_32" CACHE PATH
"The Deploy Path for the components built" )
endif()
endif()

Related

Can you specify the path to exe in qmake?

Let's talk about it in linux terms. I have a ".so" file. I want to make the executable dependent on it, look for it in the same directory. How do you do it through qmake? Or can this only be achieved through the use of QLibrary?
For example, when you have a ".so" file and want to use it in your project, in qmake you write:
LIBS += -L"path to the folder that contains your .so" -lSoName
But the path is hardcoded, as you can see, and I'm wondering what to write there to make the executable look for the ".so" in the same directory.
You use RPATH
You can configure your binary or library to find shared library (or dll) in current directory using RPATH directive that is emedded in the binary itself which the loader respects at runtime
1- Add the following in your .pro file
unix {
message("Adding RPATH to the app")
QMAKE_LFLAGS += -Wl,-rpath=\'\$$ORIGIN/\'
QMAKE_RPATH =
}
This will set RPATH of executable to current directory and your executable will first try to look for that .so in your current directory and then in standard directory (this process is explained here)
2- After you compile and create binary VERIFY that RPATH is set correctly
objdump -x <path/to/binary> |grep RPATH
it should say $ORIGIN
Compile time configuration:
CXXFLAGS += -L"/path/to/libmarylin.so/file" -lmarylin
There are a few ways to do it.
If the executable is going in the current directory, just do LIBS += -L$$(PWD) -lSoName.
If you're putting the executable into some other sub-directory, specified by some qmake variable like DESTDIR, use LIBS += -L$$(DESTDIR) (or whatever variable holds that directory).
Alternatively, you can add the directory with the executable to the runtime path of the executable, which gives the dynamic linker a list of directories to search for any unresolved libraries at runtime. This can be done with QMAKE_RPATHDIR += -L$$(PWD) and LIBS += -lSoName, which will tell the linker to look for unresolved libraries in the current directory where qmake is run.
Some operating systems may also include the current directory in the runtime search path for libraries by default, in which case just doing LIBS += -lSoName should be sufficient. That is platform-dependent, though, while the above solutions are not.

Parent CMakeLists.txt overwriting child CMakeLists.txt output directory options

I am trying to place a library from a project into a certain directory in my build output, but the parent CMakeLists.txt is overwriting the output settings.
The parent CMakeLists.txt sets all libraries to be placed in a /lib directory.
One of my libraries, however, needs to be placed into a /python library. The settings I have work on Windows. Meaning, all libs excluding my python specific library get placed in a /lib folder, and the python lib gets placed into the /python folder.
The problem appears when I build on Linux. All of the libraries, including the python specific library, get placed into the /lib folder. The FORCE option does nothing.
If I were only building for one platform, I could deal with either directory layout. But I really want to preserve the same layout across platforms.
CMakeLists.txt as follows:
-Parent CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(renderer2d)
#enable debug symbols by default
if(CMAKE_BUILD_TYPE STREQUAL "")
set(CMAKE_BUILD_TYPE Debug)
endif()
#(you can also set on cl: -D CMAKE_BUILD_TYPE=Release)
#place outside of Debug/Release folders
SET(OUTPUT_BINDIR ${PROJECT_BINARY_DIR}/bin)
MAKE_DIRECTORY(${OUTPUT_BINDIR})
SET(OUTPUT_LIBDIR ${PROJECT_BINARY_DIR}/lib)
MAKE_DIRECTORY(${OUTPUT_LIBDIR})
SET (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR} CACHE PATH "build directory")
SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_BINDIR} CACHE PATH "build directory")
IF(WIN32)
SET (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_BINDIR} CACHE PATH "build directory")
ELSE(WIN32)
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR} CACHE PATH "build directory")
ENDIF(WIN32)
# For each configuration (Debug, Release, MinSizeRel... and/or anything the user chooses)
FOREACH(CONF ${CMAKE_CONFIGURATION_TYPES})
# Go uppercase (DEBUG, RELEASE...)
STRING(TOUPPER "${CONF}" CONF)
SET("CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_LIBDIR}")
SET("CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_BINDIR}")
IF(WIN32)
SET("CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_BINDIR}")
ELSE()
SET("CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_LIBDIR}")
ENDIF()
ENDFOREACH()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#set the source directory
file(GLOB SOURCES src/*.cpp)
add_subdirectory(shape)
add_subdirectory(py_shape)
add_subdirectory(scripts)
#define sources and executable
set(EXECUTABLE_NAME "renderer2d")
add_executable(${EXECUTABLE_NAME} ${SOURCES})
#find python
find_package(PythonInterp)
find_package(PythonLibs 2.7 REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
#detect and add SFML
#this line checks a cmake file for hints on where to find cmake
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
#find any version 2.x of SFML
#see the FindSFML.cmake file for additional details and instructions
find_package(SFML 2 REQUIRED system window graphics network audio)
include_directories(${SFML_INCLUDE_DIR})
#find and include Boost python libraries
set(Boost_USE_STATIC_LIBS OFF)
find_package(Boost COMPONENTS python system filesystem REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
#link all found libraries to the executable
if(WIN32)
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE $<$<BOOL:${MSVC}>:BOOST_ALL_NO_LIB>)
endif(WIN32)
target_link_libraries(${EXECUTABLE_NAME} ${PYTHON_LIBRARIES} ${SFML_LIBRARIES} ${Boost_LIBRARIES} shape)
-Child CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(py_shape CXX)
#set file variables
file(GLOB SOURCE src/*.cpp)
file(GLOB HEADERS inc/*.hpp)
#place outside of Debug/Release folders
SET(OUTPUT_BINDIR ${CMAKE_BINARY_DIR}/python)
MAKE_DIRECTORY(${OUTPUT_BINDIR})
set(OUTPUT_LIBDIR ${CMAKEK_BINARY_DIR}/python)
MAKE_DIRECTORY(${OUTPUT_LIBDIR})
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR} CACHE PATH "build directory")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_BINDIR} CACHE PATH "build directory")
IF(WIN32)
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_BINDIR} CACHE PATH "build directory")
ELSE(WIN32)
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_LIBDIR} CACHE PATH "build directory")
ENDIF(WIN32)
#for each configuration
FOREACH(CONF ${CMAKE_CONFIGURATION_TYPES})
#Go uppercase {DEBUG, RELEASE...)
SET("CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_LIBDIR}")
SET("CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_BINDIR}")
IF(WIN32)
SET("CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_BINDIR}")
ELSE()
SET("CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONF}" "${OUTPUT_LIBDIR}")
ENDIF()
ENDFOREACH()
#find packages
find_package(PythonInterp)
find_package(PythonLibs 2.7 REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
find_package(Boost COMPONENTS python REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
find_package(SFML 2 REQUIRED system window graphics network audio)
include_directories(${SFML_INCLUDE_DIR})
#build the library
add_library(python_shape MODULE ${SOURCE})
#enable C++11 if available
target_compile_features(python_shape PRIVATE cxx_range_for)
#link library
target_link_libraries(python_shape shape ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${SFML_LIBRARIES})
#drop "lib" from the library name
set_target_properties(python_shape PROPERTIES PREFIX "")
if(WIN32)
#set extension to ".pyd"
set_target_properties(python_shape PROPERTIES SUFFIX ".pyd")
endif(WIN32)
Turning my comments into an answer
I successfully tested the following with MinGW and CMake 3.3.0 (I reduced your example a little to concentrate on the output directories):
CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(renderer2d C CXX)
# TODO: Remove, this is just for testing
file(WRITE "src/renderer2d.cpp" "int main(void) {}")
file(WRITE "py_shape/src/py_shape.cpp" "")
#enable debug symbols by default
if(CMAKE_BUILD_TYPE STREQUAL "")
set(CMAKE_BUILD_TYPE Debug)
endif()
#(you can also set on cl: -D CMAKE_BUILD_TYPE=Release)
#place outside of Debug/Release folders
#see http://www.cmake.org/Wiki/CMake_Useful_Variables
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/bin")
if(WIN32)
set(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}")
else()
set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib")
endif()
#see https://stackoverflow.com/questions/10851247/how-to-activate-c-11-in-cmake
if (CMAKE_VERSION VERSION_LESS "3.1")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "--std=gnu++11 ${CMAKE_CXX_FLAGS}")
endif()
else()
set(CMAKE_CXX_STANDARD 11)
endif()
#set the source directory
file(GLOB SOURCES src/*.cpp)
add_subdirectory(py_shape)
#define sources and executable
add_executable(${PROJECT_NAME} ${SOURCES})
add_dependencies(${PROJECT_NAME} python_shape)
py_shape/CMakeLists.txt
#set file variables
file(GLOB SOURCE src/*.cpp)
file(GLOB HEADERS inc/*.hpp)
#build the library
add_library(python_shape MODULE ${SOURCE})
set_target_properties(python_shape PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/python")
#drop "lib" from the library name
set_target_properties(python_shape PROPERTIES PREFIX "")
if(WIN32)
#set extension to ".pyd"
set_target_properties(python_shape PROPERTIES SUFFIX ".pyd")
endif()
Now python_shape.pyd is created in python subdirectory.
What I have changed/removed:
Setting the ..._OUTPUT_DIRECTORY global variables in the child CMakeLists.txt is not necessary and/or won't work
Added LIBRARY_OUTPUT_DIRECTORY to overwrite the output directory for python_shape MODULE library target (see also e.g. Custom Directory for CMake Library Output)
Removed the "by config" settings, because I think it's a feature that multi-configuration make environments like Visual Studio put different configuration binaries into equally named sub-folders.
Added some if statements around -std=c++11. It has also only to be set once in the main CMakeLists.txt
You don't need to create the output directories "manually", they are created automatically by the make environments
For the reasoning why your first approach didn't work, see my comments above.
And I wouldn't recommend the use of file(GLOB ...) to collect source files (see e.g. Why is cmake file GLOB evil? or CMake/Ninja attempting to compile deleted `.cpp` file).
Alternatives
As with all languages/frameworks like CMake there is more then one way to do things.
E.g. you could also use POST_BUILD steps to copy your binaries to a common output directory:
see Cmake: use add_custom_command to copy binary to specific location failed when location doesn't exist
and - a little more up-to-date utilizing "generator expressions" - CMake: how to specify different steps for different build configurations for Visual Studio?

How to add source files to an external project in CMake?

I want to integrate SQLite into my project using ExternalProject_Add.
cmake_minimum_required(VERSION 2.8.8)
include(ExternalProject)
# Download, configure, build and install SQLite
ExternalProject_Add(SQLite
PREFIX ${CMAKE_SOURCE_DIR}
TMP_DIR ${CMAKE_SOURCE_DIR}/temp
STAMP_DIR ${CMAKE_SOURCE_DIR}/stamp
#--Download step--------------
DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/download
URL http://www.sqlite.org/2014/sqlite-autoconf-3080704.tar.gz
URL_HASH SHA1=70ca0b8884a6b145b7f777724670566e2b4f3cde
#--Update/Patch step----------
UPDATE_COMMAND ""
#--Configure step-------------
SOURCE_DIR ${CMAKE_SOURCE_DIR}/source
CONFIGURE_COMMAND "" # How to add sqlite3.c to the target here?
#--Build step-----------------
BINARY_DIR ${CMAKE_SOURCE_DIR}/build
BUILD_COMMAND "cmake --build ."
#--Install step---------------
INSTALL_DIR ${CMAKE_SOURCE_DIR}/install
)
The build command would use the native compiler to build all source files added to the target SQLite. However, there are non. How can I add the only source file sqlite3.c to the external project within the CONFIGURE_COMMAND?
ExternalProject_Add assumes that the project you want to pull in already ships with a (possibly complex, possibly non-CMake-based) working build system.
You have two possibilities here:
You can stick with the amalgamated autoconf version of sqlite that you are currently using. In that case the CONFIGURE_COMMAND would invoke configure and the BUILD_COMMAND would invoke make. Note that this approach will not be portable to platforms that do not have autoconf installed.
You can switch to the bare-source amalgamated version of sqlite and provide your own CMakeLists.txt for building. Since sqlite can be built with a minimum of configuration and the amalgamation only consists of a single source and header file, this is not as hard as it may sound. In this case you can simply invoke cmake for configuation and building.
Note however that you cannot provide this information in-line with ExternalProject_Add. You will need an external build script, whether that is CMake, autoconf or something else.
Building on the correct answer above, this is what I came up with. Instead of adding a second file to my repository, it gets generated from the existing CMake file. Since the source directory of the external project gets cleaned on build, the generated file must be stored in a temporary location and copied into the source directory in a later step of the external project, in this case the update command.
# SQLite
cmake_minimum_required(VERSION 2.8.8)
include(ExternalProject)
# Add CMake project file
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/temp)
file(WRITE ${CMAKE_SOURCE_DIR}/temp/CMakeLists.txt
"cmake_minimum_required(VERSION 2.8.8)\n"
"set(PROJECT_NAME sqlite)\n"
"include_directories(${CMAKE_SOURCE_DIR}/source)\n"
"add_library(sqlite3 ${CMAKE_SOURCE_DIR}/source/sqlite3.c)\n"
"install(TARGETS sqlite3 DESTINATION lib)\n"
"install(FILES sqlite3.h DESTINATION include)\n")
# Download, configure, build and install.
ExternalProject_Add(SQLite
# DEPENDS
PREFIX ${CMAKE_SOURCE_DIR}
TMP_DIR ${CMAKE_SOURCE_DIR}/temp
STAMP_DIR ${CMAKE_SOURCE_DIR}/stamp
#--Download step--------------
DOWNLOAD_DIR ${SFML_PREFIX}/download
URL http://www.sqlite.org/2014/sqlite-autoconf-3080704.tar.gz
URL_HASH SHA1=70ca0b8884a6b145b7f777724670566e2b4f3cde
#--Update/Patch step----------
UPDATE_COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/temp/CMakeLists.txt
${CMAKE_SOURCE_DIR}/source/CMakeLists.txt
#--Configure step-------------
SOURCE_DIR ${CMAKE_SOURCE_DIR}/source
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_SOURCE_DIR}/install
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}
#--Build step-----------------
BINARY_DIR ${CMAKE_SOURCE_DIR}/build
BUILD_COMMAND ${CMAKE_COMMAND} --build .
#--Install step---------------
INSTALL_DIR ${CMAKE_SOURCE_DIR}/install
)

Unix - Shared Libraries Error

When I type tmadmin -v I get this error:
tmadmin: error while loading shared libraries: libgpnet.so: cannot open shared object file: No such file or directory
libgpnet.so is in my lib folder. Is there something I need to set so that tmadmin look in my lib folder?
You can check if the path to lib directory is present in the LD_LIBRARY_PATH environment variable. If it's not you can add it as:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lib

Nsis - changing installation directory

Currently I am in my installing directory say c:\Program File\My installer.I have to execute a demo.bat file that is stored at some other location say c:\Program Files\Temp\example.bat,which I have to go at that location and execute coz my example.bat has some support files that are only stored in Temp folder.
My question is how can I change my installing directory to some other directory, execute demo.bat file and come back to my original installing directory while writing an nsis script?
When talking about "installing directory", I assume you mean current/working directory in the context of a batch file.
push $outdir ;save original path
SetOutpath "$programfiles\temp" ;set currect directory
nsExec::Exec "example.bat"
pop $outdir
SetOutpath $outdir ;restore
There are several ways to execute a batch file (Expand %comspec% and pass it to Exec/ExecWait, or use one of the exec plugins (nsExec,ExecDos,ExecCmd))

Resources