How to use shared lib for static with cmake - c

I'm beginner with CMake and i would to compile my project with it.
I have the following CMakeLists.txt:
cmake_minimum_required (VERSION 2.6)
project (rt)
include_directories ("${PROJECT_BINARY_DIR}/src/")
include_directories ("${PROJECT_BINARY_DIR}/src/hook")
include_directories ("${PROJECT_BINARY_DIR}/src/light")
include_directories ("${PROJECT_BINARY_DIR}/src/move")
include_directories ("${PROJECT_BINARY_DIR}/src/object/inter")
include_directories ("${PROJECT_BINARY_DIR}/src/object/normal")
include_directories ("${PROJECT_BINARY_DIR}/src/option")
include_directories ("${PROJECT_BINARY_DIR}/src/parsing")
include_directories ("${PROJECT_BINARY_DIR}/src/ray")
include_directories ("${PROJECT_BINARY_DIR}/src/render")
include_directories ("${PROJECT_BINARY_DIR}/src/shadow")
include_directories ("${PROJECT_BINARY_DIR}/src/utils")
include_directories ("${PROJECT_BINARY_DIR}/lib/minilibx")
file(GLOB hook
"*.h"
"*.c"
)
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/src/*.c)
#set (EXTRA_LIBS ${EXTRA_LIBS} ${X11_LIBRARIES} m)
add_executable (rt ${SRC_FILES})
target_link_libraries (rt ${EXTRA_LIBS} X11 Xext m ${PROJECT_BINARY_DIR}/lib/libmlx.a)
But when I run make, my static library minilibx won't compile. with errors that all the functions from the X11 and Xext libraries are undefined.
make VERBOSE=1 result:
Linking C executable rt
/usr/bin/cmake -E cmake_link_script CMakeFiles/rt.dir/link.txt --verbose=1
/usr/bin/cc CMakeFiles/rt.dir/src/move/translation.c.o CMakeFiles/rt.dir/src/move/rotation.c.o CMakeFiles/rt.dir/src/light/light.c.o CMakeFiles/rt.dir/src/option/option.c.o CMakeFiles/rt.dir/src/option/file_option.c.o CMakeFiles/rt.dir/src/render/render.c.o CMakeFiles/rt.dir/src/hook/control.c.o CMakeFiles/rt.dir/src/ray/eye.c.o CMakeFiles/rt.dir/src/ray/ray.c.o CMakeFiles/rt.dir/src/utils/my_strlen.c.o CMakeFiles/rt.dir/src/utils/my_strncpy.c.o CMakeFiles/rt.dir/src/object/inter/plan.c.o CMakeFiles/rt.dir/src/object/inter/cone.c.o CMakeFiles/rt.dir/src/object/inter/cylinder.c.o CMakeFiles/rt.dir/src/object/inter/sphere.c.o CMakeFiles/rt.dir/src/object/inter/tore.c.o CMakeFiles/rt.dir/src/object/normal/plan.c.o CMakeFiles/rt.dir/src/object/normal/cone.c.o CMakeFiles/rt.dir/src/object/normal/cylinder.c.o CMakeFiles/rt.dir/src/object/normal/sphere.c.o CMakeFiles/rt.dir/src/parsing/scene.c.o CMakeFiles/rt.dir/src/parsing/file_access.c.o CMakeFiles/rt.dir/src/parsing/str_tool.c.o CMakeFiles/rt.dir/src/shadow/shadow.c.o CMakeFiles/rt.dir/src/main.c.o -o rt -rdynamic -lX11 -lXext -lm lib/libmlx.a
and this is an example of errors:
lib/libmlx.a(mlx_init.o): In function mlx_int_deal_shm':
mlx_init.c:(.text+0x2a): undefined reference toXShmQueryVersion'
mlx_init.c:(.text+0x104): undefined reference to `XShmPixmapFormat'
How do I solve the undefined reference errors?

I have solved the problem, the order of libs are not correct.
I just link my lib before another lib. Et voilĂ  :)
target_link_libraries (rt ${EXTRA_LIBS} ${PROJECT_BINARY_DIR}/lib/libmlx.a X11 Xext m)

CMake uses target_link_libraries to specify which libraries you link against.
In you case, it seems like you're linking against the correct libraries (target_link_libraries (rt ${EXTRA_LIBS} X11 Xext m ${PROJECT_BINARY_DIR}/lib/libmlx.a)), so my bet is they are not found.
Try running:
make VERBOSE=1
This will give you the gcc output. Paste the last couple of gcc instructions it generates here and we'll see why it didn't find your libs.

Related

How to link to FreeGlut instead of Glut on macOS using cmake and find_package?

I have the latest version of macOS Big Sur, running intel based cpu, clang12, cmake 3.19 and brew. I have installed freeglut via brew.
However whenever I called find_package(GLUT) it always finds my system GLUT (/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk/System/Library/Frameworks/GLUT.framework) over the FreeGLUT brew has installed. I have tried changing the find_package to FreeGlut with no success.
I am sure its something really simple I am missing but not knowing a lot about the macOS linking process, this has me rather confused.
Here is my cmake command line being used...
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja
Here is my cmake file.
# Set cmake minimum version.
cmake_minimum_required(VERSION 3.15)
# Set the project details.
set(PROJECT_NAME Project)
project(${PROJECT_NAME} LANGUAGES C)
# Treat warnings as errors.
option(WarningsAsErrors "WarningsAsErrors" OFF)
# If enabled, the post build symlink will copy instead.
option(CopyResources "CopyResources" OFF)
option(GenerateDoxygen "GenerateDoxygen" OFF)
# Disable in-source builds.
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
# Set build type to debug by default.
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
# Add Linux flag.
if(UNIX AND NOT APPLE)
set(LINUX TRUE)
endif()
# Define the executable.
add_executable(${PROJECT_NAME})
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11)
# Find dependencies.
# find_package(OpenGL REQUIRED COMPONENTS OpenGL)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
# Build 3rd Party Libraries
add_subdirectory(lib)
# Define source files.
add_subdirectory(src)
if (MSVC)
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()
# Treat warnings as errors if enabled.
if (WarningsAsErrors)
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:-Werror>
$<$<CXX_COMPILER_ID:MSVC>:/WX>
)
endif(WarningsAsErrors)
# Set compile flags.
target_compile_options(${PROJECT_NAME} PRIVATE
# Clang
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:
-Weverything -fcolor-diagnostics
# Disable specific warnings.
-Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded
-Wno-deprecated-declarations -Wno-exit-time-destructors
-Wno-switch-enum -Wno-weak-vtables -Wno-global-constructors>
# GCC
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wpedantic -fdiagnostics-color=always>
# Visual Studio
$<$<CXX_COMPILER_ID:MSVC>:/W4>
# Enable the clang sanitizer.
$<$<AND:$<CONFIG:Debug>,$<CXX_COMPILER_ID:Clang>,$<PLATFORM_ID:${SANITIZER_OS}>>:${SANITIZER_FLAGS}>
)
# Link against the clang sanitizer.
target_link_options(${PROJECT_NAME} PRIVATE
$<$<AND:$<CONFIG:Debug>,$<CXX_COMPILER_ID:Clang>,$<PLATFORM_ID:${SANITIZER_OS}>>:${SANITIZER_FLAGS}>
)
if (LINUX)
target_link_libraries(${PROJECT_NAME} PRIVATE -lm)
endif()
# Include and link against dependencies.
target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL OpenGL::GLU GLUT::GLUT stb OpenAL SndFile::sndfile BigBalls::Physics lua ${CMAKE_DL_LIBS})
if (GenerateDoxygen)
find_package(Doxygen)
if (DOXYGEN_FOUND)
set(DOXYGEN_IN ${CMAKE_SOURCE_DIR}/.doxyconf)
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} #ONLY)
add_custom_target(doc ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_IN}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM)
endif (DOXYGEN_FOUND)
endif (GenerateDoxygen)
# Symlink or copy the resources to the binary location.
if (NOT DisablePostBuild)
if (NOT CopyResources)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_SOURCE_DIR}/res $<TARGET_FILE_DIR:${PROJECT_NAME}>/res)
else()
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/res $<TARGET_FILE_DIR:${PROJECT_NAME}>/res)
endif()
endif()
So FindGLUT is a builtin module
ref: https://cmake.org/cmake/help/latest/module/FindGLUT.html
looking at the source code:
see https://github.com/Kitware/CMake/blob/master/Modules/FindGLUT.cmake
so it seems to use find_path()
find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR})
You can try to set GLUT_ROOT or OPENGL_LIBRARY_DIR as default path to help CMake to find the correct one...
ref https://cmake.org/cmake/help/latest/command/find_path.html

Configuring Cmake file for library dependency [duplicate]

Work on Ubuntu 16
I used g++ main.cpp -lpq command for compiler my small project. Now I use Clion and wanna do same what I do with g++. But I can't add compiler flags in cmake file and get compile error.
cmake_minimum_required(VERSION 3.5.1)
project(day_g)
set(CMAKE_CXX_FLAGS "-lpq")
add_definitions(-lpq)
message("CMAKE_CXX_FLAGS is ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
add_executable(day_g ${SOURCE_FILES})
Also I run only cmake file and get CMAKE_CXX_FLAGS with -lpq flag.
CMAKE_CXX_FLAGS is -lpq
-- Configuring done
-- Generating done
How properly add compiler flags to cmake file?
Flag -l is for linker, not for compiler. This flag is used for link with libraries. CMake has special command target_link_libraries for that purpose:
target_link_libraries(day_g pq)
-lq is not a compiler flag (CFLAGS) but a linker flag.
To pass a library in a CMake project you should use:
target_link_libraries(target_name libraries...)
Note that if you specify 'q' as library the project will link with libq.a or, if you are on windows q.dll.
... in your CMakeLists.txt the correct line to add is:
target_link_libraries(day_g pq)
Note also that when you add a CFLAG you should also "remember" the previous ones that may be added by libraries or by your platform, ie:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
To check the exact flags cmake is passing to compiler or linker you can always run, from the build directory, the following command:
make VERBOSE=1

How to include header files in external library in CMake

I have a C application which is running on Raspberry Pi 3 and currently, I have to build it on PI with Cmake. I am trying to build it on Ubuntu machine. I have added a CMAKE_TOOLCHAIN_FILE as described here.
I could run cmake. -DCMAKE_TOOLCHAIN_FILE without any problem but the "make" command is not successful and it can not find a header file inside one of the external library: "mirsdrapi-rsp". The error message is:
fatal error: mirsdrapi-rsp.h: No such file or directory
#include "mirsdrapi-rsp.h"
^
compilation terminated.
I have created a folder named "lib" and have put the "libmirsdrapi-rsp.so" file inside it.
my CMakeLists.txt is as below:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Wextra -v -g -D_XOPEN_SOURCE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wextra -v ")
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-v")
set (SDR_API_PATH ${CMAKE_SOURCE_DIR}/lib)
include_directories (include ${SDR_API_PATH})
include_directories("${CMAKE_SOURCE_DIR}/lib")
find_library(mirslocation NAMES mirsdrapi-rsp HINTS ${SDR_API_PATH} NO_CMAKE_FIND_ROOT_PATH)
message(STATUS ${mirslocation})
add_library(mirs STATIC IMPORTED)
set_target_properties(mirs PROPERTIES IMPORTED_LOCATION ${mirslocation})
target_link_libraries (raspberryPiDaemon mirs)
target_link_libraries(raspberryPiDaemon m)
Cmake is printing the right path of the library mirsdrapi-rsp while running "find_library" and as I mentioned I am getting the error message just while running "make" command and not "cmake" command.
My content of CMAKE_TOOLCHAIN_FILE is as below:
# Define our host system
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)
# Define the cross compiler locations
SET(CMAKE_C_COMPILER ${CMAKE_SOURCE_DIR}/../tools-master/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER ${CMAKE_SOURCE_DIR}/../tools-master/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc)
# Define the sysroot path for the RaspberryPi distribution in our tools folder
SET(CMAKE_FIND_ROOT_PATH ${CMAKE_SOURCE_DIR}/../tools-master/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot/SET)
# Use our definitions for compiler tools
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Search for libraries and headers in the target directories only
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
add_definitions(-Wall -std=c11)
Anybody knows how I can add the header file from mirsdrapi-rsp library to include path?
I guess that you're setting include_directories to the wrong path (it is set 2 times to ${CMAKE_SOURCE_DIR}/lib which must be the folder of libraries not the header files). Check again the correct location of the missing header file.
More precisely: you need to find the path of mirsdrapi-rsp.h and let CMake know it just like for find_library:
find_path(MIRSDRAPI_INCLUDE_DIRS NAMES mirsdrapi-rsp.h PATHS {proper-location})
if (MIRSDRAPI_INCLUDE_DIRS)
target_include_directories(raspberryPiDaemon PRIVATE ${MIRSDRAPI_INCLUDE_DIRS})
endif()
In addition, you can set the INTERFACE_INCLUDE_DIRECTORIES property to the library like this:
set_property(TARGET mirsdrapi-rsp APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MIRSDRAPI_INCLUDE_DIRS})
This way, target_include_directories might be unnecessary and target_link_directories should be enough.

CMake with flex/bison in CLion

I'm trying to translate a Makefile into CMakeLists.txt.
Makefile which works
fb1-5: fb1-5.l fb1-5.y
bison -d fb1-5.y
flex fb1-5.l
cc -o $# fb1-5.tab.c lex.yy.c -lfl
CMakeLists.txt attempt
cmake_minimum_required(VERSION 3.7)
project(calc)
set(CMAKE_C_STANDARD 99)
FIND_PACKAGE(BISON REQUIRED)
SET(BisonOutput ${CMAKE_SOURCE_DIR}/parser.c)
IF(BISON_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT ${BisonOutput}
COMMAND ${BISON_EXECUTABLE}
-d
${CMAKE_SOURCE_DIR}/fb1-5.y
COMMENT "Generating parser.c"
)
ENDIF()
FIND_PACKAGE(FLEX REQUIRED)
SET(FlexOutput ${CMAKE_SOURCE_DIR}/scanner.c)
IF(FLEX_FOUND)
ADD_CUSTOM_COMMAND(
OUTPUT ${FlexOutput}
COMMAND ${FLEX_EXECUTABLE}
${CMAKE_SOURCE_DIR}/fb1-5.l
COMMENT "Generating fb1-5.l"
)
ENDIF()
ADD_LIBRARY(calc ${BisonOutput} ${FlexOutput})
It says it finds bison and flex in clion
-- Found BISON: /usr/bin/bison (found version "3.0.4")
-- Found FLEX: /usr/bin/flex (found version "2.6.0")
But my CMake script won't generate an executable. How should I define "executable" and how can I make the CMake build script work in CLion?
But my CMake script won't generate an executable. How should I define "executable" and how can I make the CMake build script work in CLion?
I think you should at least do something like this:
add_executable(fb1-5
${BisonOutput}
${FlexOutput}
)
See add_executable.

CMake: Static and dynamic linking based on BUILD_TYPE

I am developing a small simulation software that depends on two libraries, the GSL and the libconfig. As a build system, I use CMake. For both the GSL and libconfig, I found cmake files and copied them into the cmake/ directory of my project.
The scenario is the following: I want the project to have several different build types, like debug, release, etc., but also a custom one called cluster, which adds -static to the GCC flags and links against the .a libraries of the GSL and the libconfig, which I assume exist.
My CMakeLists.txt looks like this so far:
# version
SET(PACKAGE_VERSION "1.0")
SET(PACKAGE_NAME "INTERFACE")
PROJECT(interface C CXX)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
# dirs -----------------------------------------------------
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
FIND_PACKAGE(GSL REQUIRED)
INCLUDE_DIRECTORIES(${GSL_INCLUDE_DIRS})
SET(LIBS ${LIBS} ${GSL_LIBRARIES})
FIND_PACKAGE(LibConfig REQUIRED)
INCLUDE_DIRECTORIES(${LIBCONFIG_INCLUDE_DIRS})
SET(LIBS ${LIBS} ${LIBCONFIG_LIBRARIES})
CONFIGURE_FILE("res/config.h.in" "config.h")
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
SET_DIRECTORY_PROPERTIES(PROPERTIES
ADDITIONAL_MAKE_CLEAN_FILES "config.h"
)
# compilation ----------------------------------------------
ADD_EXECUTABLE( interface
interface.c interface.h config.h
helpers.c
output.c
lattice.c
genetic.c
)
# optional CFLAGS
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -std=c99")
SET(CMAKE_C_FLAGS_RELEASE "-O3 -ffast-math")
SET(CMAKE_C_FLAGS_CLUSTER "-O3 -ffast-math -static")
SET(CMAKE_C_FLAGS_DEBUG "-g")
SET(CMAKE_C_FLAGS_PROFILE "-g -ffast-math -pg")
TARGET_LINK_LIBRARIES(interface m ${LIBS})
# installation --------------------------------------------
INSTALL(TARGETS interface DESTINATION bin)
This adds the -static to the compiler, when I use -DCMAKE_BUILD_TYPE=cluster. The thing is, that it still links against the .so versions of the libs, which causes gcc to throw errors. At least the FindLibConfig.cmake scripts sets both a LIBCONFIG_LIBRARY and a LIBCONFIG_STATIC_LIBRARY variable, which I could use.
What is the most elegant or smart way to reach my goal?
Acording to cmake documentation, cmake uses the variable BUILD_SHARED_LIBS to determine the default for add_library().
If you set to ON cmake will assume all add_library() call will be as
add_library(target SHARED lib1 lib2 ...)
For example something like -DBUILD_SHARED_LIBS=ON on the cmake command line may do what you are asking.
I solved it like this:
The User can specify an additional variable -DSTATIC_LINKING=TRUE. Then, the script looks like this. (Only the important parts for the static linking and compilation are shown!)
# determine, whether we want a static binary
SET(STATIC_LINKING FALSE CACHE BOOL "Build a static binary?")
# do we want static libraries?
# When STATIC_LINKING is TRUE, than cmake looks for libraries ending
# with .a. This is for linux only!
IF(STATIC_LINKING)
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
ENDIF(STATIC_LINKING)
# set -static, when STATIC_LINKING is TRUE and set LINK_SEARCH_END_STATIC
# to remove the additional -bdynamic from the linker line.
IF(STATIC_LINKING)
SET(CMAKE_EXE_LINKER_FLAGS "-static")
SET_TARGET_PROPERTIES(surface PROPERTIES
LINK_SEARCH_END_STATIC 1)
ENDIF(STATIC_LINKING)

Resources