I have makefile(.mke) on Windows and I need to count directories in a folder which start with "Install" and then make if clause to throw an exception if there are more than one directory like this.
For example:
Files: Install.1.0, Install.2.0, Install.3.0..
I have $(SrcRoot) variable and I need to count directories in this folder then make if clause that "if (numberOfDirs > 1) throw an error."
In my example there would be an exception because there are 3 Install.. folders.
If by "throw an exception" you mean abort Make with an error message, this will do it:
INSTALLS := $(wildcard $(SrcRoot)/Install*)
ifneq (,$(word 2,$(INSTALLS)))
$(error there are too many Install directories)
endif
Related
Short version (TL;DR)
Using CMake with the PkgConfig module I try to print all the include directories for a library I need for my project, let's call it thelibrary. I do this by printing the value of the THELIBRARY_INCLUDE_DIRS variable. The list of include directories is printed, but one directory is missing.
This really surprised it, as if I type the following on a terminal:
pkg-config thelibrary --cflags
then all the include directories are printed, including the one missing from THELIBRARY_INCLUDE_DIRS.
The same happens if I try to print the value of THELIBRARY_CFLAGS.
How is this possible? Where is the mistake? (Hoping it is a mistake of mine)
Details
Context
I am working on a C++ Cmake project which is compiled correctly under Mac OS but not under Linux (Ubuntu), and when investigating on the possible reasons I found the issue below.
Problem
I included the PkgConfig module in file CMakeLists.txt by writing:
find_package(PkgConfig REQUIRED)
After that, in order to use the library, I set the PKG_CONFIG_PATH environment variable by writing:
set(ENV{PKG_CONFIG_PATH} "/usr/local/opt/thelibrary/pkgconfig:$ENV{PKG_CONFIG_PATH}")
Finally, I put this instruction to search the library.
pkg_check_modules(THELIBRARY thelibrary)
Finally, in order to debug, I have tried to print the list of included directories by writing:
MESSAGE( STATUS "THELIBRARY DIRS: " ${THELIBRARY_INCLUDE_DIRS} )
The problem is, it worked, in fact it printed a list of include directories, but the problem is that the most important one is missing. In fact, the output is something like:
/opt/auxlib1/include/opt/auxlib2/include ...
where auxlib1, auxlib2 etc. are auxiliary include directories I need to compile.
But I also expected the dir /opt/thelibrary/include in output, which is printed if I use the pkg-config command on the terminal as said at the beginning. How is it possible that only that directory is not printed?
Thanks to the suggestion by Tsyvarev (deleting CMakeCache.txt), I understood what the cause was, and since this may happen to other people, I hope this explanation helps.
The reason why the directory /opt/thelibrary/include wasn't appearing in THELIBRARY_INCLUDE_DIRS is that file CMakeCache.txt contained information about a previous version of the library, whose header files were installed in a directory with a slightly different name, which was removed when that previous version was uninstalled.
Since that directory does not exist anymore, then it doesn't appear in THELIBRARY_INCLUDE_DIRS, and the new directory does not appear simply because the file CmakeCache.txt was still pointing to the previous version.
Solution: delete CmakeCache.txt and re-run cmake.
we have a tree shaped directory structure in our project like:
project_dir/public_include
public_include has dir1, dir2 and dir3
now, I want to include directories based on an option
if(option A)
include_directories(project_dir/public_include/dir1)
else
include_directories(project_dir/public_include/dir3
project_dir/public_include/dir2)
endif()
The header files are independent.
It is not working!!! Am I missing something???
How about options ? Try using option(option_A "include dir 1" ON) at the top of your CMakeLists.txt. It will set option_A=ON by default and your if statement should work.
The problem:
I want to add the boost numeric bindings as an include directory in my build. This is typically compiled as:
c++ -I/where/you/want/to/install/it/include/boost-numeric-bindings
All of the header files I reference from my program are all relative to this directory, so in CMake I want to find this directory (wherever it is installed on the parent system) and add it to the include_directories.
What I'm looking for:
Something like this:
find_directory(BNB_INCLUDE_DIR boost-numeric-bindings)
include_directories(${BNB_INCLUDE_DIR})
But the find_directory command does not exist. Am I missing something here?
What I've tried:
I've tried:
find_path(BNB_INCLUDE_DIR boost/numeric/bindings/traits/ublas_vector.hpp)
include_directories(${BNB_INCLUDE_DIR})
(which is the first file I need from the library) but this gives me the full path to the file and not the path to the directory containing the entire prefix to the file specified in the command.
See this answer for information on how to write a cmake Find file. As an example, here is one that I wrote for the lm-sensors library:
# - Try to find the LM_SENSORS library.
#
# The following are set after configuration is done:
# LM_SENSORS_FOUND
# LM_SENSORS_INCLUDE_DIRS
# LM_SENSORS_LIBRARY_DIRS
# LM_SENSORS_LIBRARIES
find_path(LM_SENSORS_INCLUDE_DIR NAMES sensors/sensors.h)
find_library(LM_SENSORS_LIBRARY NAMES libsensors sensors)
message("LM_SENSORS include dir = ${LM_SENSORS_INCLUDE_DIR}")
message("LM_SENSORS lib = ${LM_SENSORS_LIBRARY}")
set(LM_SENSORS_LIBRARIES ${LM_SENSORS_LIBRARY})
set(LM_SENSORS_INCLUDE_DIRS ${LM_SENSORS_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
# Handle the QUIETLY and REQUIRED arguments and set the LM_SENSORS_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(LM_SENSORS DEFAULT_MSG
LM_SENSORS_LIBRARY LM_SENSORS_INCLUDE_DIR)
mark_as_advanced(LM_SENSORS_INCLUDE_DIR LM_SENSORS_LIBRARY)
Change the above to match your library (boost-numeric-bindings), name the file Findboost-numeric-bindings.cmake, and put it in your cmake module dir (or create one of these in your source tree).
Then in your CMakeLists.txt file, do this:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} your_cmake_module_dir)
find_package (boost-numeric-bindings REQUIRED)
include_directories(${BOOST_NUMERIC_BINDINGS_INCLUDE_DIR})
Then, assuming you don't have the library installed in a standard location, run cmake as follows:
cmake -D CMAKE_PREFIX_PATH:STRING="/where/you/have/installed/it/" <source path>
Edit
Make sure you have defined a project before you call find_path or find_package. Otherwise CMAKE_SYSTEM_INCLUDE_PATH will not be set. For example:
find_path (BOOST_STATE_HPP boost/statechart/state.hpp)
message ("CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}")
message ("CMAKE_SYSTEM_INCLUDE_PATH=${CMAKE_SYSTEM_INCLUDE_PATH}")
message ("CMAKE_SYSTEM_FRAMEWORK_PATH=${CMAKE_SYSTEM_FRAMEWORK_PATH}")
message ("CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
message ("BOOST_STATE_HPP=${BOOST_STATE_HPP}")
project (my_project)
will result in the following cmake output:
CMAKE_FIND_ROOT_PATH=
CMAKE_SYSTEM_INCLUDE_PATH=
CMAKE_SYSTEM_FRAMEWORK_PATH=
CMAKE_PREFIX_PATH=
BOOST_STATE_HPP=BOOST_STATE_HPP-NOTFOUND
whereas this:
project (my_project)
find_path (BOOST_STATE_HPP boost/statechart/state.hpp)
message ("CMAKE_FIND_ROOT_PATH=${CMAKE_FIND_ROOT_PATH}")
message ("CMAKE_SYSTEM_INCLUDE_PATH=${CMAKE_SYSTEM_INCLUDE_PATH}")
message ("CMAKE_SYSTEM_FRAMEWORK_PATH=${CMAKE_SYSTEM_FRAMEWORK_PATH}")
message ("CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
message ("BOOST_STATE_HPP=${BOOST_STATE_HPP}")
results in sucessfully finding state.hpp and setting BOOST_STATE_HPP to /usr/include, as you desire:
CMAKE_FIND_ROOT_PATH=
CMAKE_SYSTEM_INCLUDE_PATH=/usr/include/w32api;/usr/X11R6/include;/usr/include/X11;/usr/pkg/include;/opt/csw/include;/opt/include;/usr/openwin/include
CMAKE_SYSTEM_FRAMEWORK_PATH=
CMAKE_PREFIX_PATH=
BOOST_STATE_HPP=/usr/include
I have to make a one click build of a projet made for Cmake ( already works on Linux) with a batch file that downloads all the 3rd party libraries and compiles them. (win64)
If posible i dont want to change projets CMakeLists.txt.
I already build the project in VS2010 GUI. and i had to change the folowing:
a. had to change Configuration properties-C++-Command line: added /DWNT /D "CAD_STATIC"
b. had to add a long list of libraries in Configuration properties- Linker input- additional dependencies.
c. add library directories for those libraries
d. add include directories.
The project compiled and worked ok.
Now i need to make the same with only batch commands.
I already build the project file with cmake with:
cmake ..\projectsource -G "Visual Studio 10 Win64" -DGLEW_LIBRARY:FILEPATH=%myroot%\glew\trunk\lib\Release\glew.lib -DGLUT_glut_LIBRARY:FILEPATH=%myroot%\freeglut\trunk\lib\Release\freeglut.lib -DMKL_LIBRARIES:FILEPATH=%myroot%\mkl\em64t\lib\mkl_core.lib -DOpenCascade_INCLUDE_DIR:PATH=%myroot%\OpenCascade
Now i need a command like "devenv project.sln /useenv " that does the same as the stuff i did under #2.
I tried with a env include & lib like:
set "include=%myroot%\glew\trunk\include;%myroot%\freeglut\trunk\include;%myroot%\mkl\include;%myroot%\qt\include;%myroot%\OpenCascade\include\oce;%myroot%\trimo\src\CadModel;%include%"
set "lib=%myroot%\glew\trunk\lib\Release\*.lib;%myroot%\freeglut\trunk\lib\Release\*.lib;%myroot%\mkl\em64t\lib\*.lib;%myroot%"\qt\lib\*.lib;%myroot%\OpenCascade\Win64\lib\*.lib;%lib%"
All the help is very much appreciated. I'm stuck. Thanks
Edit:
I got another problem:
How can i unlink a library that gets linked in a project.sln automaticly by cmake?
will "lib=%myroot%\glew\trunk\lib\Release*.lib; link all the .lib files like u would get if u put all the libs in a vs2010 gui -Linker input- additional dependencies?
If you're already setting the required include and lib variables, then probably all that's missing is:
set "cl=/DWNT /DCAD_STATIC"
then you should be able to use
devenv project.sln /useenv /build
Note, you've also got libpath available to set search paths for the libraries if required.
Answers to further questions
I don't know of a way to do that.
No. I hadn't noticed you were doing that in your original question - sorry! The LIB env var sets search paths in which libs could be found, it's not for the full path to the actual lib itself.
What you're trying to achieve is exactly the sort of scenario at which CMake excels. You're fighting CMake here when it's probably the solution to the problems :-)
If I were you, I'd edit the CMakeLists.txt to include things like:
SET(MY_ROOT <path to %myroot%>)
FIND_LIBRARY(GLEW_LIBRARY glew ${MY_ROOT}/glew/trunk/lib/Release)
IF(NOT GLEW_LIBRARY)
MESSAGE(FATAL_ERROR "glew.lib not found in ${MY_ROOT}/glew/trunk/lib/Release")
ENDIF()
FIND_LIBRARY(GLUT_glut_LIBRARY freeglut ${MY_ROOT}/freeglut/trunk/lib/Release)
IF(NOT GLUT_glut_LIBRARY)
MESSAGE(FATAL_ERROR "freeglut.lib not found in ${MY_ROOT}/freeglut/trunk/lib/Release")
ENDIF()
FIND_LIBRARY(MKL_LIBRARIES mkl_core ${MY_ROOT}/mkl/em64t/Release)
IF(NOT MKL_LIBRARIES)
MESSAGE(FATAL_ERROR "mkl_core.lib not found in ${MY_ROOT}/mkl/em64t/Release")
ENDIF()
INCLUDE_DIRECTORIES(${MY_ROOT}/OpenCascad)
ADD_DEFINITIONS(-DWNT -DCAD_STATIC)
TARGET_LINK_LIBRARIES(<your target>
${GLEW_LIBRARY}
${GLUT_glut_LIBRARY}
${MKL_LIBRARIES}
<any other libs...>
)
This is all Windows-specific, and Release-specific. You could adapt the FIND_LIBRARY calls to cater for Unix/OSX options too, or you could wrap this in IF(WIN32) ... ENDIF() blocks.
You could also do FIND_LIBRARY calls for the Debug versions too if required (giving them different variable names) and adding them like:
TARGET_LINK_LIBRARIES(<your target>
optimized ${GLEW_LIBRARY}
optimized ${GLUT_glut_LIBRARY}
optimized ${MKL_LIBRARIES}
debug ${GLEW_LIBRARY_DEBUG}
debug ${GLUT_glut_LIBRARY_DEBUG}
debug ${MKL_LIBRARIES_DEBUG}
<any other libs...>
)
You'll also be able to remove whatever libraries you want from whatever targets you want by modifying the list of libs passed in the TARGET_LINK_LIBRARIES call(s).
If you want to grab all *.lib files in a directory, add something like this:
FILE(GLOB ALL_GLEW_LIBS "${MY_ROOT}/glew/trunk/lib/Release/*.lib")
TARGET_LINK_LIBRARIES(<your target> ${ALL_GLEW_LIBS})
If you do use the GLOB call, and you also need Debug and Release, be sure to prefix each list item with debug or optimized as appropriate, e.g.
FOREACH(GLEW_ITR ${ALL_GLEW_LIBS_RELEASE})
SET(ALL_GLEW_LIBS ${ALL_GLEW_LIBS} optimized ${GLEW_ITR})
ENDFOREACH()
FOREACH(GLEW_ITR ${ALL_GLEW_LIBS_DEBUG})
SET(ALL_GLEW_LIBS ${ALL_GLEW_LIBS} debug ${GLEW_ITR})
ENDFOREACH()
TARGET_LINK_LIBRARIES(<your target> ${ALL_GLEW_LIBS})
If all this is then catered for by CMake, you don't need to set any env vars in the batch script; you just do:
devenv project.sln /build
Have a SomeLib.pro file that contains:
CONFIG += debug
TEMPLATE = lib
TARGET = SomeLib
..
Then in a dependent SomeApp.pro:
..
debug:LIBS += -lSomeLib_debug
..
How can I force SomeApp to build if I touched SomeLib in qmake?
It's ugly because you need to give the exact library file name, but this should work:
TARGETDEPS += libfoo.a
QT Creator will do the work if you click "Add library..." in the context menu of the project that should include the library.
These variables are configured automatically for you:
LIBS
INCLUDEPATH
DEPENDPATH
PRE_TARGETDEPS
See also http://doc.qt.digia.com/qtcreator-2.1/creator-project-qmake-libraries.html
In reply to Zahir's comment, it's perhaps worth pointing out that stating this dependency in qmake files is unnecessary if using DLLs, but is essential if your exe depends on a static library.
qmake does not provide this ability.
Instead, put your app and lib in subdirectories, then create a Makefile in their parent directory that looks something like this:
all: FRC
cd Somelib && qmake && $(MAKE)
cd SomeApp && qmake && $(MAKE)
FRC:
Then always run make from this directory.
I used:
POST_TARGETDEPS += c:/open-en/lib/win32mingw/libosal_based.a
It works, but is clumsy since it is necessary specify full path to library, which is different for every operating system/compiler.
surely that can't be possible, you are talking about using qmake to do a reverse dependency lookup? so what u want is for it to build app B (and any other app dependent on library A) after you've made a change to library A?
that's a bit like saying recompile all visual basic apps if vbrun300.dll is updated?