PLplot linker error - c

I am trying to use PLplot for visualization in a C project.
However, although the headers and the libraries seem to be correctly included (cmake returns no error), when I try to actually use some PLplot functions, I get errors similar to undefined reference to 'c_plinit' and ld returned 1 exit status
I guess it is a linker problem and it seems like a common problem. However, the stuff I found on google are either not applicable for my case or not detailed enough for a beginner like me.
Note that if I add in the CMakeLists.txt:
message(${PLplot_INCLUDE_DIRS})
message(${PLplot_LIBRARY_DIRS})
message(${PLplot_LIBRARIES})
I get the following output:
/usr/local/include/plplot
/usr/local/lib
/usr/local/lib/libplplotcxxd.so
Please help!
EDIT:
The relevant lines from CMakeLists.txt are as follows:
# The directory with the FindPLplot module
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
FIND_PACKAGE(PLplot REQUIRED)
SET(PLplot_LIBRARIES ${PLplot_LIBRARIES} ${PLplot_cxx_LIBRARY})
INCLUDE_DIRECTORIES(${PLplot_INCLUDE_DIRS})
LINK_DIRECTORIES(${PLplot_LIBRARY_DIRS})
ADD_EXECUTABLE(main main.c)
TARGET_LINK_LIBRARIES(main ${PLplot_LIBRARIES})
INSTALL(TARGETS main DESTINATION bin)
And then, under a folder called cmake, there is a FindPLplot.cmake module similar to the one here: https://github.com/mrquincle/polychronization/blob/master/cmake/

Related

M1 mac using clion with cmake and homebrew to use sdl2_gfx error [duplicate]

Looking around on the net I have seen a lot of code like this:
include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)
target_include_directories(app SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS})
target_link_libraries(app ${SDL2_LIBRARIES})
However that seems to be the wrong way about doing it, as it only uses the include directories and libraries, but ignored defines, library paths and other flags that might be returned by pkg-config.
What would be the correct way to do this and ensure that all compile and link flags returned by pkg-config are used by the compiled app? And is there a single command to accomplish this, i.e. something like target_use(app SDL2)?
ref:
include()
FindPkgConfig
First of, the call:
include(FindPkgConfig)
should be replaced with:
find_package(PkgConfig)
The find_package() call is more flexible and allows options such as REQUIRED, that do things automatically that one would have to do manually with include().
Secondly, manually calling pkg-config should be avoid when possible. CMake comes with a rich set of package definitions, found in Linux under /usr/share/cmake-3.0/Modules/Find*cmake. These provide more options and choice for the user than a raw call to pkg_search_module().
As for the mentioned hypothetical target_use() command, CMake already has that built-in in a way with PUBLIC|PRIVATE|INTERFACE. A call like target_include_directories(mytarget PUBLIC ...) will cause the include directories to be automatically used in every target that uses mytarget, e.g. target_link_libraries(myapp mytarget). However this mechanism seems to be only for libraries created within the CMakeLists.txt file and does not work for libraries acquired with pkg_search_module(). The call add_library(bar SHARED IMPORTED) might be used for that, but I haven't yet looked into that.
As for the main question, this here works in most cases:
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
...
target_link_libraries(testapp ${SDL2_LIBRARIES})
target_include_directories(testapp PUBLIC ${SDL2_INCLUDE_DIRS})
target_compile_options(testapp PUBLIC ${SDL2_CFLAGS_OTHER})
The SDL2_CFLAGS_OTHER contains defines and other flags necessary for a successful compile. The flags SDL2_LIBRARY_DIRS and SDL2_LDFLAGS_OTHER are however still ignored, no idea how often that would become a problem.
More documentation here http://www.cmake.org/cmake/help/latest/module/FindPkgConfig.html
If you're using cmake and pkg-config in a pretty normal way, this solution works.
If, however, you have a library that exists in some development directory (such as /home/me/hack/lib), then using other methods seen here fail to configure the linker paths. Libraries that are not found under the typical install locations would result in linker errors, like /usr/bin/ld: cannot find -lmy-hacking-library-1.0. This solution fixes the linker error for that case.
Another issue could be that the pkg-config files are not installed in the normal place, and the pkg-config paths for the project need to be added using the PKG_CONFIG_PATH environment variable while cmake is running (see other Stack Overflow questions regarding this). This solution also works well when you use the correct pkg-config path.
Using IMPORTED_TARGET is key to solving the issues above. This solution is an improvement on this earlier answer and boils down to this final version of a working CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
project(ya-project C)
# the `pkg_check_modules` function is created with this call
find_package(PkgConfig REQUIRED)
# these calls create special `PkgConfig::<MODULE>` variables
pkg_check_modules(MY_PKG REQUIRED IMPORTED_TARGET any-package)
pkg_check_modules(YOUR_PKG REQUIRED IMPORTED_TARGET ya-package)
add_executable(program-name file.c ya.c)
target_link_libraries(program-name PUBLIC
PkgConfig::MY_PKG
PkgConfig::YOUR_PKG)
Note that target_link_libraries does more than change the linker commands. It also propagates other PUBLIC properties of specified targets like compiler flags, compiler defines, include paths, etc., so, use the PUBLIC keyword with caution.
It's rare that one would only need to link with SDL2. The currently popular answer uses pkg_search_module() which checks for given modules and uses the first working one.
It is more likely that you want to link with SDL2 and SDL2_Mixer and SDL2_TTF, etc... pkg_check_modules() checks for all the given modules.
# sdl2 linking variables
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2 SDL2_ttf SDL2_mixer SDL2_image)
# your app
file(GLOB SRC "my_app/*.c")
add_executable(my_app ${SRC})
target_link_libraries(my_app ${SDL2_LIBRARIES})
target_include_directories(my_app PUBLIC ${SDL2_INCLUDE_DIRS})
target_compile_options(my_app PUBLIC ${SDL2_CFLAGS_OTHER})
Disclaimer: I would have simply commented on Grumbel's self answer if I had enough street creds with stackoverflow.
Most of the available answers fail to configure the headers for the pkg-config library. After meditating on the Documentation for FindPkgConfig I came up with a solution that provides those also:
include(FindPkgConfig)
if(NOT PKG_CONFIG_FOUND)
message(FATAL_ERROR "pkg-config not found!" )
endif()
pkg_check_modules(<some-lib> REQUIRED IMPORTED_TARGET <some-lib>)
target_link_libraries(<my-target> PkgConfig::<some-lib>)
(Substitute your target in place of <my-target> and whatever library in place of <some-lib>, accordingly.)
The IMPORTED_TARGET option seems to be key and makes everything then available under the PkgConfig:: namespace. This was all that was required and also all that should be required.
There is no such command as target_use. But I know several projects that have written such a command for their internal use. But every project want to pass additional flags or defines, thus it does not make sense to have it in general CMake. Another reason not to have it are C++ templated libraries like Eigen, there is no library but you only have a bunch of include files.
The described way is often correct. It might differ for some libraries, then you'll have to add _LDFLAGS or _CFLAGS. One more reason for not having target_use. If it does not work for you, ask a new question specific about SDL2 or whatever library you want use.
If you are looking to add definitions from the library as well, the add_definitions instruction is there for that. Documentation can be found here, along with more ways to add compiler flags.
The following code snippet uses this instruction to add GTKGL to the project:
pkg_check_modules(GTKGL REQUIRED gtkglext-1.0)
include_directories(${GTKGL_INCLUDE_DIRS})
link_directories(${GTKGL_LIBRARY_DIRS})
add_definitions(${GTKGL_CFLAGS_OTHER})
set(LIBS ${LIBS} ${GTKGL_LIBRARIES})
target_link_libraries([insert name of program] ${LIBS})

symbol lookup error: symbol exists, I know where it is, how do I get my SO to "see it"?

I am writing a plugin module for a larger program, written in C++. I have never written a SO library before. My module compiles and links correctly (I think) however the main program loading the SO crashes with the error symbol lookup error.
The module I am writing worked fine, until I started to try and use other libraries within it. (Specifically caffe)
There is a main program which is developed by another group
I am writing a plugin module for this program
My plugin module uses functions / code from Caffe (from the libcaffe.so file, Caffe itself is a compiled binary just to add to confusion)
The main program crashes with the following error
/path-to-binary/binary-name: symbol lookup error: ./build/libTestModule.so: undefined symbol: _ZN5caffe2db5GetDBERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
I tried adding export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib to my .bashrc.
I did this because (after some internet searching - I don't actually understand what I am doing here) I ran
nm -g libcaffe.so | grep _ZN5caffe2db5GetDBERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
in the folder /usr/lib and that symbol exists in libcaffe.so.
00000000001cbb30 T _ZN5caffe2db5GetDBERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
libcaffe.so is in /usr/lib and contains the symbol that my program cannot find.
My understanding is that (for some reason which is not known to me) I have to set LD_LIBRARY_PATH to /usr/lib so that my program can find libcaffe.co and the symbols contained within it.
However I would have assumed that since /usr/lib contains loads of "default" .so files, that this would be searched regardsless of whether LD_LIBRARY_PATH was set, ie shouldn't this directory be searched by default?
Regardless of the above question, I don't know what I should try next.
How can I get my program to find the symbol above in libcaffe.so?
CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(TestModule)
find_package(Falaise REQUIRED)
add_library(TestModule SHARED TestModule.h TestModule.cpp)
set(Caffe_INCLUDE_DIRS "/usr/include/caffe")
set(Caffe_LIBRARIES "/usr/lib/libcaffe.so")
target_link_libraries(TestModule PUBLIC Falaise::FalaiseModule)
Your libTestModule.so is, you say, dependent on libcaffe.so but you are
not linking it. This:
cmake_minimum_required(VERSION 3.3)
project(TestModule)
find_package(Falaise REQUIRED)
add_library(TestModule SHARED TestModule.h TestModule.cpp)
target_link_libraries(TestModule PUBLIC Falaise::FalaiseModule caffe)
is how you would do so.

CMakeLists.txt configuration - simple but stuck - library not been added to generated project

I was originally following this tutorial: http://www.opengl-tutorial.org/miscellaneous/building-your-own-c-application/
just after about half way down, from where it says "Adding a source file in a project"
I created from this my CMakeLists.txt file as so:
cmake_minimum_required (VERSION 2.6)
project (Cube_Project)
find_package(OpenGL REQUIRED)
add_executable(Cube
main.cpp
)
include_directories(
external/glfw-2.7.6/include/
external/glm-0.9.4.0/
external/glew-1.9.0/include/
.
)
set(ALL_LIBS
${OPENGL_LIBRARY}
GLFW_276
GLEW_190
)
target_link_libraries(Cube
${ALL_LIBS}
)
but when I generate the project, I get this error:
ld: library not found for -lGLFW_276
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Any ideas?
I think maybe I'm not using the right names in the set(....) section? My three libs are in a folder called external, which is the top level of the project (i.e. CMakeLists is also here).
I put a zip of the project if anyone wants to take a look at the folder layout of output XCode project structure: http://heather.sh/OpenGL_Project.zip
Thanks,
The library is not in the linker's library search path.
The target_link_libraries command is is very straightforward: It simply passes on all of its arguments to the linker without bothering whether any of those libraries actually exist.
In your case, the GLFW_276 library is missing (and possibly the GLEW_190 as well, since the error occurs before that one is being processed). Make sure the library is actually installed on your system and its filename actually matches the name you use here (eg. libGLFW_276.so).
Once you verify that you have the required file, you need to make sure that the linker is able to find it. If the file is not located in one of the standard directories, use either link_directories to add its location to the search path, or find_library to obtain the full path to the library file, which can then be given to target_link_libraries.

CMake doesn't appear to be linking CppUnit

This may already be answered somewhere, so please point me in the right direction if so - I couldn't find anything that matched my specific problem when googling!
I've got some CppUnit tests that I'm trying to run.
My top-level CMakeLists.txt contains:
include_directories(
${CPPUNIT_INC}
)
link_directories(
${CPPUNIT_LIB}
)
Both of which are set correctly: I print the paths earlier in the CMakeLists.txt file, and they're correct.
In the subfolder, I have;
add_executable(test-lumberjack TestLumberjack.cpp)
target_link_libraries(
test-lumberjack
Lumberjack
CppUnit
${CMAKE_DL_LIBS}
)
INSTALL(TARGETS test-lumberjack DESTINATION ${PROJECT_OUTPUT_TEST_DIR})
ADD_TEST(NAME test-lumberjack COMMAND "${PROJECT_OUTPUT_TEST_DIR}/test-lumberjack")
However, when I run the tests (either by running the file or using ctest -V), I see the usual linker error EDIT: it's not a linker error, see answer below
The library definitely exists, in the path set earlier in the top level CMakeLists.txt.
I'm stumped! I'm assuming there's something key that I'm totally missing, but I haven't a clue what it is. If you'd like more info, let me know and I'll add it.
Cheers.
I'm an idiot: the CppUnit folder wasn't in my library path. Should've realised this when it was crashing at runtime, not during compilation... Doh!

How do you export a system library using cmake?

How can I export the libraries that a cmake library depends on, such that an executable depending on that library does not have to manually depend on the dependencies of that library?
That's a bit of a mouthful, so here's an example:
dummy (application) ----> depends on liba
liba ----> depends on libpng
Compiling dummy generates errors:
-- Found LIBPNG
-- Found LIBA
-- Configuring done
-- Generating done
-- Build files have been written to: /home/doug/projects/dummy/build
Linking C executable dummy
../deps/liba/build/liba.a(a.c.o): In function `a_dummy':
/home/doug/projects/dummy/deps/liba/src/a.c:6: undefined reference to `png_sig_cmp'
collect2: ld returned 1 exit status
make[2]: *** [dummy] Error 1
make[1]: *** [CMakeFiles/dummy.dir/all] Error 2
make: *** [all] Error 2
I can fix that by adding this into CMakeLists.txt for dummy:
TARGET_LINK_LIBRARIES(dummy png)
However, dummy has no knowledge of how liba implements its api. At some point that may change to being libjpg, or something else, which will break the dummy application.
After getting some help from the cmake mailing list I've been directed to this example for exporting things:
http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file
However, following that approach leaves me stuck at this line:
export(TARGETS ${LIBPNG_LIBRARY} FILE "${PROJECT_BINARY_DIR}/ALibraryDepends.cmake")
Clearly I'm missing something here; this 'export' command looks like its designed to export sub-projects to a high level; ie. nested projects inside liba.
However, that is not the problem here.
When configuring liba (or any cmake library) I will always generate a list of dependencies which are not part of that project.
How can I export those so they appear as part of LIBA_LIBRARY when I use find_package() to resolve liba?
Using static libraries is not an option (static library for something that links to opengl? no.)
Given your comment to arrowdodger's answer about the fear of
installing something would mess up your system I chose to give
a conceptional comment in form of an answer because of its
length.
Chaining cmake project works via find_package, which looks for
*Config.cmake and *-config.cmake files.
Project A's CMakeLists.txt:
#CMakeLists.txt
project(A)
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/AConfig.cmake share/A/cmake
)
#AConfig.cmake
message("Yepp, you've found me.")
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/test-install ..
$ make install
Project B's CMakeLists.txt:
project(B)
find_package(A)
Then
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/test-install ..
$ make install
results in
...
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Yepp, you've found me.
B found A because it installed AConfig.cmake into a location
where cmake will find it 'share/A/cmake' AND was given the same
value for CMAKE_INSTALL_PREFIX.
Now this is that. Lets think about what you can do in
AConfig.cmake: AFAIK everything you want to. But the most common
task is to pull information about the targets of A via include(),
do some additional find_package invoctions for 3rd party
packages (HINT HINT) and create the variables
A_LIBRARIES
A_INCLUDE_DIRS
What you want to include is a file that was created by
install(EXPORT A-targets
DESTINATION share/A/cmake
)
in A's CMakeLists.txt , where A-targets refers to a global cmake
variable that accumulated all target informations when used in
install(TARGETS ...
EXPORT A-targets
...
)
statments. What is created at make install is
/tmp/test-install/share/A/cmake/A-targets.cmake
which then resides alongside AConfig.cmake in the same directory.
Please take another look at the wiki page on how to use this file
within AConfig.cmake.
Regarding the export() command: This comes handy if your
projects have gotten HUGE and it takes a considerable amount of
time to install them. To speed things up, you want to use what's
in A's build/ directory directly. It's an optimization and also
explained in the wiki. It still works via find_package(), see
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:export
But I strongly suggest that you go for the usual make install
route for now.
I found my own solution to this problem using the accepted solution above, which I leave here for others:
In liba/CMakeLists.txt:
# Self
set(A_INCLUDE_DIRS ${A_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/include")
set(A_LIBRARIES ${A_LIBRARIES} "${PROJECT_BINARY_DIR}/liba.a")
# Libpng
FIND_PACKAGE(libpng REQUIRED)
set(A_INCLUDE_DIRS ${A_INCLUDE_DIRS} ${LIBPNG_INCLUDE_DIRS})
set(A_LIBRARIES ${A_LIBRARIES} ${LIBPNG_LIBRARIES})
ADD_LIBRARY(a ${SOURCES})
# Includes
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})
# Allow other projects to use this
configure_file(AConfig.cmake.in "${PROJECT_BINARY_DIR}/AConfig.cmake")
In liba/AConfig.cmake:
set(A_LIBRARIES #A_LIBRARIES#)
set(A_INCLUDE_DIRS #A_INCLUDE_DIRS#)
In dummy/CMakeLists.txt:
FIND_PACKAGE(A REQUIRED)
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(dummy ${A_LIBRARIES})
This yields an AConfig.cmake that reads:
set(A_LIBRARIES /home/doug/projects/dummy/deps/liba/build/liba.a;/usr/lib/libpng.so)
set(A_INCLUDE_DIRS /home/doug/projects/dummy/deps/liba/include;/usr/include)
And a verbose compile that reads:
/usr/bin/gcc -std=c99 -g CMakeFiles/dummy.dir/src/main.c.o -o dummy -rdynamic ../deps/liba/build/liba.a -lpng
Which is exactly what I was looking for.
If liba doesn't provide any means to determine it's dependencies, you can't do anything.
If liba is library developed by you and you are using CMake to build it, then you should install libaConfig.cmake file with liba itself, which would contain necessary definitions. Then you include libaConfig in dummy's CMakeLists.txt to obtain information about how liba have been built.
You can look how it's done in LLVM project, relevant files have cmake.in extension
http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/modules/
In the end, in dummy project you should use
target_link_libraries( ${LIBA_LIBRARIES} )
include_directories( ${LIBA_INCLUDE_DIR} )
link_directories( ${LIBA_LIBRARY_DIR} )
If that liba is used only by dummy, you can build it from single CMake project. This is more convenient, since you don't need to install liba each time you recompile it and it will be rebuilt and relinked with dummy automatically every time you run make.
If you liked this approach, the only thing you should do - define in liba' CMakeLists.txt variables you need with PARENT_SCOPE option (see set() command manual).
Finally, you can use shared libs, .so's don't have such problem.

Resources