I'm trying to incorporate or-tools into my cmake project.
I've tried some of the suggestions given by the project maintainers, who give a few different ways to integrate or-tools in the readme and in a template project. I've tried both, yielding the same result.
The first method is building locally and using cmake's find_package
:
################
## OR_TOOLS ##
################
message(STATUS "Installing OR-Tools...")
# Download and install or-tools at configure time
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/ortools.CMakeLists.txt
${CMAKE_BINARY_DIR}/ortools-download/CMakeLists.txt)
# CMake configure
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/ortools-download)
if(result)
message(FATAL_ERROR "CMake step for ortools failed: ${result}")
endif()
# CMake Build/Install
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/ortools-download)
if(result)
message(FATAL_ERROR "Build step for ortools failed: ${result}")
endif()
message(STATUS "Installing OR-Tools...DONE")
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/deps)
find_package(ortools REQUIRED)
where in the cmake
directory I have a file ortools.CmakeLists.txt
:
cmake_minimum_required(VERSION 3.8)
project(ortools-download NONE)
include(ExternalProject)
ExternalProject_Add(ortools_project
GIT_REPOSITORY https://github.com/google/or-tools.git
GIT_TAG "stable"
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
CMAKE_ARGS
"-G@CMAKE_GENERATOR@"
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
"-DBUILD_DEPS=ON"
"-DBUILD_SAMPLES=OFF"
"-DBUILD_EXAMPLES=OFF"
"-DBUILD_TESTING=OFF"
"-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/deps"
)
and the second is to use cmake's FetchContent
.
include(FetchContent)
FetchContent_Declare(
ortools
GIT_REPOSITORY https://github.com/google/or-tools.git
GIT_TAG stable
)
set(BUILD_DEPS ON)
set(BUILD_SAMPLES OFF)
set(BUILD_EXAMPLES OFF)
FetchContent_MakeAvailable(ortools)
set(requiredlibs ${requiredlibs} ortools::ortools)
Both give the same error, at runtime:
ERROR: Something is wrong with flag 'flagfile' in file 'Users/username/project-root/cmake-build-debug/ortools-download/ortools_project-prefix/src/ortools_project-build/_deps/absl-src/absl/flags/parse.cc'. One possibility: file 'Users/username/project-root/cmake-build-debug/ortools-download/ortools_project-prefix/src/ortools_project-build/_deps/absl-src/absl/flags/parse.cc' is being linked both statically and dynamically into this executable. e.g. some files listed as srcs to a test and also listed as srcs of some shared lib deps of the same test.
For reference, I'm on an Apple Silicon Mac, using cmake 3.22.3, compiling with the flag:
-DCMAKE_APPLE_SILICON_PROCESSOR=arm64
. I've tried both -DCMAKE_BUILD_TYPE=Release
and -DCMAKE_BUILD_TYPE=Debug
.
EDIT:
I partially figured it out, however I still have a question: I want to compile a dynamic library from many shared libraries in my project. The static libraries need to be linked to ortools
because they reference that library. However, I then want to build a shared library that merges all the separate static libraries together, this doesn't work. Why is that the case, and is there a way to fix it?
Below is my current solution so if anyone else has this issue they can reference. I ended up using the FetchContent
method, with a few modifications.
The error gives a hint as to what was happening: "is being linked both statically and dynamically into this executable".
In c++ there are two types of libraries: static and dynamic. My code builds many static libraries and links them to a dynamic library, which is then linked to the executable file.
project structure:
.
├── CMakeLists.txt
├── src
│ ├── CMakeLists.txt # creates the dynamic library
│ ├── [various .cc/.h files]
│ ├── staticlib1
│ │ ├── CMakeLists.txt # creates a static library
│ │ └── [various .cc/.h files]
│ └── staticlib2
│ ├── CMakeLists.txt # creates another static library
│ └── [various .cc/.h files]
└── main.cc
The key is that ortools::ortools
can only be linked to either multiple static libraries, or multiple dynamic libraries. It cannot be linked to both static and dynamic libraries.
In src/CMakelists.txt
I create a dynamic library and was linking to ortools:
project(project)
SET(SOURCE_FILES_SRC
example.cc
)
add_subdirectory(staticlib1)
set(requiredlibs ${requiredlibs} staticlib1)
add_subdirectory(staticlib2)
set(requiredlibs ${requiredlibs} staticlib2)
add_library(${DISPATCHER_LIB} SHARED ${SOURCE_FILES_SRC})
target_link_libraries(${DISPATCHER_LIB} ${requiredlibs} ortools::ortools) # linking to dynamic(shared) ortools lib
However, I was also linking to ortools::ortools
in the static libraries in src/staticlib1/CMakeLists.txt
which caused the issue:
project(project)
set(staticlib1_SOURCE_FILES
example2.cc)
add_library(staticlib1 STATIC ${staticlib1_SOURCE_FILES})
set_property(TARGET staticlib1 PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(staticlib1 ${requiredlibs} ortools::ortools) # linking to static ortools
To fix this, changed the dynamic library to a static library
project(project)
SET(SOURCE_FILES_SRC
example.cc
)
add_subdirectory(staticlib1)
set(requiredlibs ${requiredlibs} staticlib1)
add_subdirectory(staticlib2)
set(requiredlibs ${requiredlibs} staticlib2)
add_library(${DISPATCHER_LIB} ${SOURCE_FILES_SRC}) # now a static library
target_link_libraries(${DISPATCHER_LIB} ${requiredlibs})
I also had to change the FetchContent
block in CMakeLists.txt
to disable building the ortools dynamic libraries.
set(FETCHCONTENT_QUIET OFF)
include(FetchContent)
FetchContent_Declare(
ortools
GIT_REPOSITORY https://github.com/google/or-tools.git
GIT_TAG stable
)
set(BUILD_SHARED_LIBS OFF) # disables dynamic(shared) library building
set(BUILD_DEPS ON)
set(BUILD_SAMPLES OFF)
set(BUILD_EXAMPLES OFF)
FetchContent_MakeAvailable(ortools)
As I stated above, at the beginning of the edit, I would like this line
add_library(${DISPATCHER_LIB} ${SOURCE_FILES_SRC}) # now a static library
in src/CMakeLists.txt
to be a dynamic library:
add_library(${DISPATCHER_LIB} SHARED ${SOURCE_FILES_SRC}) # now a static library
is there a way to make that work given that I need ortools to link to the static libraries that it is composed of?
project(ortools-download NONE)
to specify the language:project(ortools-download LANGUAGES C CXX)
. $\endgroup$FetchContent
version worked fine for me on an M1. Otherwise was getting some compiler error when compiling CBC (it's a dep). Also, addset(FETCHCONTENT_QUIET OFF)
to see what's going on. $\endgroup$