I am new to CPP, to GUROBI and specially to CMAKE. I am working on a project and I am trying to compile a C++ program, that needs to link to the GUROBI external libraries libgurobi81.so and libgurobi_c++.a as explained in the GUROBI site here and here.
The structure of my cmake and my project is something like this:
-folder1
--src
---cmake
--gurobi
---lib
----libgurobi81.so
----libgurobi_c++.a
My code compiles correctly, but it only fails when linking with the libraries.
I tried to make CMAKE to find the libraries:
find_library(C_GUROBI_LIB NAMES libgurobi81.so gurobi81 gurobi81_light
PATHS ${LD_LIBRARY_PATH}
/path/to/folder1/gurobi/lib/
)
find_library(CPP_GUROBI_LIB NAMES gurobi_c++
PATHS ${LD_LIBRARY_PATH}
/path/to/folder1/folder1/gurobi/lib/
)
and then to print it:
message("C_GUROBI_LIB points to " ${C_GUROBI_LIB})
message("CPP_GUROBI_LIB points to " ${CPP_GUROBI_LIB})
However, even if the library is in that folder CMAKE do not find it and shows nothing:
C_GUROBI_LIB points to
CPP_GUROBI_LIB points to
I found a possible solution, adapted from here:
set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
I had some other issues, for example the library was compiled for 64 bits, and also that CMAKE did not allow to add Shared files. So I got to change some parameters, but even with that, CMAKE did not found the file.
Related
So from what I understand, a static compiled mylib.a file should just be usable as plug-and-play. But I can't use it without the source code, I'm trying to avoid that.
I adapted this tutorial to compile using CMake with the following directory structure:
/
lib
libmy_math.a
main.cpp
my_math.h
my_math.cpp
CMakeLists.txt
The contents of the files are exactly as in the tutorial. The only added file is CMakeLists.txt which basically just runs the library compiling part before building:
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(Test)
### Uncomment this ONCE to compile a libmy_math.a file
# add_library(my_math STATIC my_math.cpp)
add_executable(Test main.cpp)
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
As the CMake file says, uncommenting Line 5 compiles the library, which is then linked to my code when compiling.
I'm trying to package my code so that I don't show my client the source code for the compiled library (my_math), but if I delete the my_math.h and my_math.cpp files, I get a "file not found" error on import:
/Users/Joe/Desktop/Test/main.cpp:1:10: fatal error: 'my_math.h' file not found
#include "my_math.h"
^~~~~~~~~~~
I thought you could compile libraries without needing the source code. What am I missing here?
A static library does not contain each and every definition a header can contain - think of macros, etc. Thus you still need the header. However, you don't need the .cpp anymore to link the library.
Besides the problem stated in Iorro's answer the find_library call here will not work as expected.
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
What this does is, while running CMake, look for the my_math.a file. However, at that point of the build process, my_math.a has not been built yet. You're just running CMake for the first time, so all you have is source files. Nothing has been compiled yet.
What you want to do instead is link to the library target directly, as CMake already knows about that and can resolve the dependency on its own. So you need to replace the two lines above with:
target_link_libraries(Test PUBLIC my_math)
This now introduces a curious asymmetry in how your test consumes the library (as it is part of the same build) vs. how your clients consume the same library (which are not part of the same build and thus need to do a find_package call before they can use it). Look at CMake's config-file packages for a mechanism that allows you to restore symmetry here, at the cost of a significant amount of boilerplate required in your CMake script.
I have c++ code which is built using cmake. I have written a class which depends on a library called Gurobi. One of Gurobi's competitors is CPLEX, another library which allows for similar optimization tasks. I have to rewrite my classes in CPLEX for a research project (because our funding comes from an agency which only has access to CPLEX). Therefore, I want to change my cmake file so that it looks for Gurobi and CPLEX and compiles my code using the GurobiClass.cpp file if it finds Gurobi, and uses the CPLEX.cpp file if it finds cplex.
I'm basically asking how to ignore code in the compilation step, so that a user does not have to have both libraries to compile my code.
I'm sure this question has been asked already, but I'm not sure what the correct name for this is / what to search, so I'm asking it again, but feel free to point me to online resources.
Thanks for any help you can provide!
Considering you haven't posted any code, there are a number of options. If the libraries use CMake themselves, and come with a FindGurobi.cmake or FindCPLEX.cmake, you can use CMake's find_package() to locate them. You can determine which files to include (and libraries to link) to your target using if-statements. A simple example would be something like this:
find_package(Gurobi)
find_package(CPLEX)
if(Gurobi_FOUND)
# Compile with Gurobi classes.
add_library(MyLibrary
TopLevelClass.cpp
GurobiClass1.cpp
GurobiClass2.cpp
...
)
target_include_directories(MyLibrary PUBLIC ${Gurobi_INCLUDE_DIR})
target_link_libraries(MyLibrary PUBLIC ${Gurobi_LIBRARIES})
elseif(CPLEX_FOUND)
# Compile with CPLEX classes.
add_library(MyLibrary
TopLevelClass.cpp
CPLEXClass1.cpp
CPLEXClass2.cpp
...
)
target_include_directories(MyLibrary PUBLIC ${CPLEX_INCLUDE_DIR})
target_link_libraries(MyLibrary PUBLIC ${CPLEX_LIBRARIES})
else()
message(FATAL_ERROR "Neither Gurobi nor CPLEX library was found.")
endif()
If you are hard-coding the paths to these libraries somehow, you could also do something like this (to check if the library files exist):
set(Gurobi_INCLUDE_DIR /path/to/local/gurobi/include)
set(Gurobi_LIBRARY /path/to/local/gurobi/lib/gurobi.lib)
set(CPLEX_INCLUDE_DIR /path/to/local/CPLEX/include)
set(CPLEX_LIBRARY /path/to/local/CPLEX/lib/cplex.lib)
if(EXISTS ${Gurobi_LIBRARY})
# Compile with Gurobi classes...
elseif(EXISTS ${CPLEX_LIBRARY})
# Compile with CPLEX classes...
else()
message(FATAL_ERROR "Neither Gurobi nor CPLEX library was found.")
endif()
I have a project using 3 CMakeLists.txt:
CMakeLists.txt C is my executable and depends on
CMakeLists.txt B which is a static lib and that depends on
CMakeLists.txt A which is also a static lib and depends on an external lib
In CMakeLists.txt C I specify my dependency against B using using target_link_libraries() and I do the same for the dependency of B against A. In CMakeLists.txt A I specify the dependency against the external lib.
I would expect this to work but C actually complains at link-time and I can only get it to work by specifying a dependency in C against the external lib.
Note that the external lib is dynamic (a .so file).
This looks weird to me, no? Anyone understands what is going on?
Thanks,
Antoine.
That should work. I bet there's a bug in the CMakeLists.txt.
View real dependencies
Check it with:
cmake .. --graphviz=deps.dot
xdot deps.dot
It will show a pretty picture of the dependency tree that cmake sees.
If you don't have xdot, export it to a png:
dot -Tpng deps.dot -o deps.png
firefox deps.png
Library not found ?
Another possibility is that the external library can't actually be found. Use find_library rather than just putting the library name:
find_library(FAIL failingmadly)
if (NOT FAIL)
message(FATAL_ERROR "Couldn't find the failingmadly library")
endif()
target_link_libraries(my_lib_a ${FAIL})
Position independent code?
Another possibility when linking static libs with dependencies on shared libs is the PIC complaints. You could add this in cmake before compiling anything:
add_definitions(-fPIC)
Good luck.
I've looked around, and it doesn't seem that the solution to my problem has been discussed anywhere. So, I write here.
I create a CMake project for generation of several Python libraries. I use Boost.Python to wrap my C++ code, CMake to build dynamic libraries. Everything is on Cygwin platform. The topmost level of the project is pretty standard- eventually it leads to the source directory via:
ADD_SUBDIRECTORY("src")
The /src directory contains two sub-folders - mmath and ann - each is intended for its own library. The CMake file at this level is:
MESSAGE("Going into subdirectory mmath...")
ADD_SUBDIRECTORY("mmath")
MESSAGE("Going into subdirectory ann...")
ADD_SUBDIRECTORY("ann")
So we build the mmath library first:
file(GLOB MMATH_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
file(GLOB MMATH_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${MMATH_HEADERS})
SET( ext_libs
${Boost_LIBRARIES}
${PYTHON_LIBRARIES}/libpython2.6.dll
)
ADD_LIBRARY(mmath SHARED ${MMATH_SRC})
TARGET_LINK_LIBRARIES(mmath ${ext_libs})
and it works perfectly. The resulting dynamic library can then be imported in Python as a module (in cygwin the library is prepended with "cyg" prefix, instead of "lib"). Among other things, the library defines a class DATA, which is essentially a customized container (a collection of variables of standard types), so very simple.
Now, when CMake proceeds into the /src/ann directory, it tries to build the corresponding cygann.dll (cygwin convention) library, which depends on the mmath library we have built already. The CMake script is:
file(GLOB ANN_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
file(GLOB ANN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${ANN_HEADERS})
SET( ext_libs1
mmath
${Boost_LIBRARIES}
${PYTHON_LIBRARIES}/libpython2.6.dll
)
ADD_LIBRARY(ann SHARED ${ANN_SRC})
TARGET_LINK_LIBRARIES(ann ${ext_libs1})
In the src/ann directory we have a file defining the class Ann, which has the members of type std::vector. It is here where linking problem revels itself: the DATA class causes some problems on the linking stage - the "undefined reference" error. The errors indicate that neither constructor nor destructor for the DATA class are defined:
CMakeFiles/ann.dir/libann.cpp.o: In function `Destroy<libmmath::DATA>':
/usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/bits/stl_construct.h:93: undefined reference to `libmmath::DATA::~DATA()'
CMakeFiles/ann.dir/libann.cpp.o: In function `Construct<libmmath::DATA, libmmath::DATA>':
/usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/bits/stl_construct.h:83: undefined reference to `libmmath::DATA::DATA(libmmath::DATA const&)'
So I'm wondering what could be the problem. Is this related to CMake features, cygwin tricks or is it something regarding the code itself? Well, i feel that the problem is less likely related to the code itself, since it works in standard utilization (static exe or just a single dynamic library). It is more likely that it is something about CMake or cygwin that I'm missing. But what? Please, help. Thank you in advance.
I'm new in using CMake, and I need to link openscenegraph library to my shared library.
Part of code responsible for it looks like this:
add_library (MyLib SHARED ${${PROJECT_NAME}_sources})
target_link_libraries(MyLib ${OPENSCENEGRAPH_LIBRARIES})
Im finding osg like this:
find_package(OpenSceneGraph REQUIRED osgDB osgUtil osg osgViewer osgGA osgShadow)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
add_definitions(${OPENSCENEGRAPH_DEFINITIONS})
And everything looks like it is linking, CMake isn't giving me any errors, but during building with Visual Studio 2010 I got errors like:
fatal error C1083: Cannot open include file: 'osg/Node': No such file or directory
Usually I was finding answers to all my questions without asking them (this is my first question here).
This may be trivial, but can someone tell me what am I doing wrong, and how can I make it work?
This doesn't seems related to linking, but to compile. The error says that MSVC doesn't find the file 'osg/Node' in the list of included directories.
Somewhere in your source code, you probably have an include like
#include "osg/Node"
so compiler will search for a file called 'Node' in the directory called 'osg' in one of the 'include directories'.
In CMake, print the list of include dirs for OpenSceneGraph (after find_package(OpenSceneGraph ...)
message(STATUS "OSG Incl dirs: ${OPENSCENEGRAPH_INCLUDE_DIRS}")
then check this list. If it contains something like C:/path/to/openscenegraph/include then you should import Node using
#include "osg/Node"
If instead you have a folder for each module (ex: C:/path/to/openscenegraph/include/osg) so you must use
#include "Node"
If you don't want to modify includes in your code, then you have to add C:/path/to/openscenegraph/include in your include directories (from CMake script)
include_directories(C:/path/to/openscenegraph/include)