CMake library not found - cmake

I try to run the makefile that using cmake produced. It generate an error
ld: library not found for -lhello
clang: error: linker command failed with exit code 1 (use -v to see invocation)
the file directory is:
the cmakelists.txt is:
the main.c file is:
the ERROR:
I think I set the right directory. How to solve this ERROR?

CMake has a system if you want to link libraries. For many standard libraries we have cmake modules which will allow you to use the find_package command. This will set some variables for include directories and libraries. If there is no such thing for your library you can use find_path for the include files and find_library to search for a library.
Here is what you could do (untested, just out of my head):
add_executable(main main.c)
target_include_directories(
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC ${CMAKE_SOURCE_DIR}/include/hello
)
find_library (
HELLO_LIB
NAMES hello libhello # what to look for
HINTS "${CMAKE_SOURCE_DIR}/lib" # where to look
NO_DEFAULT_PATH # do not search system default paths
)
# check if we found the library
message(STATUS "HELLO_LIB: [${HELLO_LIB}]")
if (NOT HELLO_LIB)
message(SEND_ERROR "Did not find lib hello")
endif
target_link_libraries(main
${HELLO_LIB}
)
Use message to debug your cmake files. If you define the library in cmake as well you can link directly against the cmake target.

When your library isn't in a standard path liking /usr/lib, you should use link_directories() in your CMakeLists.txt to specify a non-standard library path which contains your library. Notice that you MUST put your link_directories() ahead of add_executable() as the following shows:
link_directories(../../lib)
add_executable(newhello main.c)
include_directories(../../include)
target_link_libraries(newhello hello)

Related

ld: library not found for -lnetcdf

I am new to CMake. I can not resolve the flowing error. Could someone help me?
------------ERROR--------------
ld: library not found for -lnetcdf
collect2: error: ld returned 1 exit status
make[3]: *** [NUP] Error 1
make[2]: *** [CMakeFiles/NUP.dir/all] Error 2
make[1]: *** [CMakeFiles/NUP.dir/rule] Error 2
make: *** [NUP] Error 2
------------------- CMake File------------------
cmake_minimum_required(VERSION 3.10.0)
project(NUP Fortran)
enable_language(Fortran)
set(INCLUDE_FILE /usr/local/Cellar/netcdf/4.7.4/include)
set(lib_FILE /usr/local/Cellar/netcdf/4.7.4/lib)
find_package(netcdf REQUIRED)
if(netcdf_FOUND)
include_directories(${INCLUDE_FILE})
set(
SOURCE_FILES
${PROJECT_BINARY_DIR} unpack.f90
)
add_executable(NUP ${SOURCE_FILES} )
target_link_libraries(NUP netcdf)
endif()
--------------unpack.f90-------------------
PROGRAM unpack_array
IMPLICIT NONE
INCLUDE 'netcdf.inc'
INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(12,307)
......
I am using MACOS Catalina. Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.4.0
If you're using find_package() to find NetCDF on your machine, you shouldn't need to manually specify the paths as you have. Let find_package do that for you.
Note: CMake doesn't ship with a Find Module for NetCDF, so you'll have to download one (like this one) from the internet. Then, you need to tell CMake where to locate this FindNetCDF.cmake file on your system using CMAKE_MODULE_PATH. Finally, you can use the NetCDF::NetCDF imported target to link NetCDF to your project's targets.
cmake_minimum_required(VERSION 3.10.0)
project(NUP Fortran)
# Don't need this, you already enabled Fortran above in the 'project' call.
enable_language(Fortran)
set(INCLUDE_FILE /usr/local/Cellar/netcdf/4.7.4/include)
set(lib_FILE /usr/local/Cellar/netcdf/4.7.4/lib)
# Add the location of the 'FindNetCDF.cmake' file to your module path.
list(APPEND CMAKE_MODULE_PATH "/path/to/downloaded/find/module")
# Then, call find package for NetCDF.
find_package(NetCDF REQUIRED)
if(${NetCDF_FOUND})
# Don't need this if you use the imported target below.
include_directories(${INCLUDE_FILE})
# Don't provide directories with source file list.
set(SOURCE_FILES
${PROJECT_BINARY_DIR}
unpack.f90
)
add_executable(NUP ${SOURCE_FILES})
# Use the imported target to link netcdf instead.
target_link_libraries(NUP PRIVATE NetCDF::NetCDF)
endif()
As commented, there are other approaches to adding NetCDF to your CMake project. If you use a different find module, the syntax of the provided NetCDF CMake variables and imported targets may be slightly different. You'll have to examine the find module file itself.
In addition, you may instead use a CMake package configuration file (e.g. netCDFConfig.cmake) downloaded from the internet to add NetCDF to your project. In this case, you would still use find_package(), but you would specify the configuration file's location using CMAKE_PREFIX_PATH, rather than CMAKE_MODULE_PATH.
You can find detailed descriptions for each of these approaches in the CMake find_package() documentation. I highly encourage you spend some time to read it.

How to correctly add path to libfiles?

My project has a dependency library in ~/SimGrid/lib directory.
How can I correctly add it to my CMakeLists.txt?
Now I try link_directories(/home/whoami/SimGrid/lib), but it doesn't help and gives:
[ 5%] Linking CXX executable CSim2Sim
/usr/bin/ld: cannot find -lsimgrid
collect2: error: ld returned 1 exit status
My full CMakeLists.txt is here:
project(CSim2Sim)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O0")
set(SOURCE_FILES src/main.cpp)
add_executable(CSim2Sim ${SOURCE_FILES})
include_directories(/home/whoami/SimGrid/include)
link_directories(/home/whoami/SimGrid/lib)
target_link_libraries(CSim2Sim simgrid)
On Linux, linker expects library filename to be prefixed with "lib":
/home/whoami/SimGrid/lib/libsimgrid.so
If your library file has no such prefix, it cannot be found by the linker using plain library name.
As opposite, specifying full library filename in target_link_libraries call works always:
# Assume filename of the library is 'simgrid.so'
target_link_libraries(CSim2Sim /home/whoami/SimGrid/lib/simgrid.so)
In that case link_directories() call isn't needed.
link_directories only tells CMake what directories to look inside for the libraries you want to link to, not what libraries you want to link. My suggestion would be to create a file named SimGrid.cmake and add the following:
# -*- cmake -*-
set(SIMGRID_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}/SimGrid/include
)
set(SIMGRID_LIBRARIES
simgrid.a
simgrid2.a # etc for the names of the actual libs you want to link
)
In your CMakeLists.txt add include(SimGrid) to pull the new file in.
Then in your CmakeLists.txt use the new variables and target_link_libraries which is the function you use to tell the linker what libraries you want to link:
include_directories(${SIMGRID_INCLUDE_DIRS})
target_link_libraries(CSim2Sim ${SIMGRID_LIBRARIES})
Of course, you could just add it all to your single CMakeLists.txt, but dividing it up is good practice to keep things manageable.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O0")
set(SOURCE_FILES src/main.cpp)
add_executable(CSim2Sim ${SOURCE_FILES})
link_directories(${CMAKE_SOURCE_DIR}/SimGrid/lib)
include_directories(${CMAKE_SOURCE_DIR}/SimGrid/include)
set(SIMGRID_LIBRARIES
simgrid.a
simgrid2.a
)
target_link_libraries(CSim2Sim ${SIMGRID_LIBRARIES})
My recommendation is to find the libs your project depends on and link it to the target. Thus any absolut or relative path are not in the cmake file but detected while run of cmake.
See How can I find a library name of .so file?

How to use libxml2 with CMake?

I am using CLion editor (with CMake) for my C project,
I've never used an external library though,
my question is how do I link an external lib (for ex. libxml2) to my project?
I've seen some questions similar to this but none worked for me.
My project is compiled on Windows, and I have libxml .dll, include, and .lib files(binaries for Windows).
Edit: My CMakeLists.txt file after the answer suggested:
cmake_minimum_required(VERSION 3.2)
project(time_table)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES
course.c
course.h
day.h
defines.h
find_tables.c
find_tables.h
item.h
parse_info.c
parse_info.h
table.c
table.h
time_table.c grades.c grades.h)
link_libraries(C:/Users/Gal/Desktop/time_table/libxml2-2.7.8.win32/lib)
add_executable(time_table ${SOURCE_FILES})
target_link_libraries(time_table libxml2)
and this is what I get:
"C:\Program Files (x86)\JetBrains\CLion 1.1.1\bin\cmake\bin\cmake.exe" --build C:\Users\Gal\.clion11\system\cmake\generated\2eda76ff\2eda76ff\Debug --target time_table -- -j 8
[ 14%] Linking C executable time_table.exe
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find -llibxml2
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe[3]: *** [time_table.exe] Error 1
CMakeFiles\time_table.dir\build.make:225: recipe for target 'time_table.exe' failed
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/time_table.dir/all' failed
mingw32-make.exe[2]: *** [CMakeFiles/time_table.dir/all] Error 2
CMakeFiles\Makefile2:78: recipe for target 'CMakeFiles/time_table.dir/rule' failed
mingw32-make.exe[1]: *** [CMakeFiles/time_table.dir/rule] Error 2
What is wrong?
There is a key work for libraries installed on your machine. <lib_name>_INCLUDE_DIR and <lib_name>_LIBRARIES once you have done find_package. This works for me.
find_package(LibXml2 REQUIRED)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/<my_stuff> ${LIBXML2_INCLUDE_DIR})
add_executable(<my_exe> <my_source_files>)
target_link_libraries(<my_exe> ${LIBXML2_LIBRARIES})
---- Just a note for your curiosity ----
If you ever needed to build (1) a (static) library of your calculations, maybe reusable, and (2) an executable that uses that library and LIBXML2, do this.
find_package(LibXml2 REQUIRED)
# add a calculation library: file "lib<mycalc>.a"
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/<your header files folder> ${LIBXML2_INCLUDE_DIR})
add_library(<mycalc> STATIC ${CMAKE_CURRENT_SOURCE_DIR}/<your src files folder>)
target_link_libraries(<mycalc> ${LIBXML2_LIBRARIES})
# add the executable: file <my_exe>
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/<your header files folder> ${LIBXML2_INCLUDE_DIR})
add_executable(<my_exe> <your exe src files>)
target_link_libraries(<my_exe> <mycalc> ${LIBXML2_LIBRARIES})
Assume that full path to the library(.lib) can be expressed as
<library_dir>/<library_name>.lib
For compile executable, which uses this library, you need:
CMakeLists.txt:
link_libraries(<library_dir>)
add_excutable(<my_exe> ..)
target_link_libraries(<my_exe> <library_name>)
For use(run) compiled executable, you need to have <library_name>.dll either under one of the directory, listed in the PATH environment variable, or within same directory with executable.
there are 32bit and 64bit version of libxml2, to be found here.
you can put them below the PATH - or the C:\Windows directory.
With moderns CMake (version 3.2 or newer), it got much easier:
Search for the library. CMake has an according find module, thus it boils down to
find_package(LibXml2 REQUIRED)
Then you can link the library it to your target foo
target_link_libraries(foo PUBLIC LibXml2::LibXml2)
That's it folks! No fiddling around with headers and libraries, all done automatically.
If you have not installed the library, you might want to set LibXml2_DIR to the location where LibXml2 is located, i.e., by passing -DLibXml2_DIR=C:\software\libxml2 to your CMake call. That will help CMake finding LibXml2.

Getting a CMake Error: Cannot specify link libraries for target which is not built by the project

I am implementing CMake in my code but I'm getting the error
"Cannot specify link libraries for target "Qt5::Widgets" which is not built by the project".
Below are the contents of the CMakeLists.txt:
#Specify the version being used aswell as the language
cmake_minimum_required(VERSION 2.6)
#Name your project here
project(eCAD)
#Sends the -std=c++11 flag to the gcc compiler
ADD_DEFINITIONS(-std=c++11)
#This tells CMake to main.cpp and name it eCAD
add_executable(eCAD main.cpp)
#include the subdirectory containing our libs
add_subdirectory (gui)
include_directories(gui)
#include Qt directories
find_package(Qt5Widgets)
find_package(Qt5Core)
find_package(Qt5Designer)
SET(QT_USE_QTDESIGNER ON)
#link_libraries
target_link_libraries(Qt5::Widgets Qt5::Core)
In addition to the accepted answer: An important detail is to place target_link_libraries after the add_executable and find_package lines, so all linked components are known.
The first argument of target_link_libraries is the target name:
target_link_libraries(eCAD Qt5::Widgets Qt5::Core)
Also, do not confuse target name with the project name:
a command project specifies a project name, but
a target is the one created with add_executable, add_library or add_custom_target.
The error message is about the target.
Set you_lib_name before setting target_link_libraries
set(you_lib_name libname)
target_link_libraries(you_lib_name Qt5::Widgets Qt5::Core)

Using CMake with ifort compiler

I am using CMake 2.8.7 on a Linux machine with Intel 11.0 compilers. I am trying to use CMake for the first time as I would like to build this project on both Windows and Linux machines.
I though of using a simple approach first and used a standard Hello World example:
My src/HelloWorld.f90:
!Test helloworld in Fortran using Cmake
program hello
print *, "Hello World!"
end program hello
My main CMakeLists.txt:
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
enable_language (Fortran)
project(helloworld Fortran)
add_subdirectory(src)
SET_TARGET_PROPERTIES(helloworld PROPERTIES LINKER_LANGUAGE FORTRAN)
My src/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.7)
# Include the directory itself as a path to include directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# For a large number of source files you can create it in a simpler way
# using file() function:
file(GLOB helloworld_SOURCES *.f90)
I still get an error which says CMAKE_FORTRAN_LINK_EXECUTABLE variable missing. I looked at Abinader's CMake tutorial#1, but haven't had success so far.
any suggestions?? Thanks in advance !
Not a direct answer, as I've never used fortran with cmake, but I can see a few issues here.
First of all: where is your target helloworld defined? project is not a target.
Secondly: where do you use helloworld_SOURCES variable?
Try a more regular way. In your src/CMakeLists.txt add line at the end of file with:
add_executable(helloworld ${helloworld_SOURCES})
Also remove SET_TARGET_PROPERTIES(helloworld PROPERTIES LINKER_LANGUAGE FORTRAN) from main one as it should not be necessary.
Last advice: try not to use file(GLOB ). It is better to define list of all files manualy.
Probably the upper-case "FORTRAN", when setting the linker language is the problem. Try writing it as "Fortran" as in the enable_language statement. CMake derives the variables it uses from the language and this causes CMake to look for CMAKE_FORTRAN_LINK_EXECUTABLE instead of CMAKE_Fortran_LINK_EXECUTABLE.
As also mentioned by Michal, the add_executable has to be added to your CMakeLists.txt.
I tested your issue with the following CMake configurations files
main CMakeLists.txt:
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
enable_language (Fortran)
project(helloworld Fortran)
add_subdirectory(src)
src/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.7)
add_executable(helloworld HelloWorld.f90)
under Linux for following versions:
ifort (IFORT) 16.0.0.20150815
cmake version 2.8.12.2
I prefer to use cmake-gui. There you can define the ifort compiler as follows:
After definition of source code and binary folder, e.g. build, press "Configure" and select
Click "Next" and define the following compilers
Click "Finish" and "Generate".
Go to build/src folder and execute make. The helloworld executable is generated with ifort successfully and could be called here.
Hint: If ifort is already the default native compiler on your Linux computer then you don't have to specify it in cmake-gui and can go ahead with the first option "Use default native compilers".
Hope it helps.
Let's try this step-by-step:
1) Your Fortran Hello, world is OK!
src/hello.f90
!Test helloworld in Fortran using Cmake
program hello
print *, "Hello World!"
end program hello
2) Now let's write the "inner" CMakeLists.txt
src/CMakeLists.txt
add_executable(helloworld hello.f90)
set_target_properties(
helloworld
PROPERTIES
LINKER_LANGUAGE Fortran
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build)
Here we've created an executable file, which you haven't in your question. Also, we've set its linker language to Fortran (it's case-sensitive parameter!) and the output directory for the compiled file.
3) Now we'll create the "main" CMakeLists.txt
CMakeLists.txt
# States that CMake required version must be greater than 2.8.7
cmake_minimum_required(VERSION 2.8.7)
project(helloworld Fortran)
add_subdirectory(src)
Here we've specified the src subdirectory with inner CMakeLists.txt and the compiler language - it's enough to use project() function, there's not need to use it together with enable_language().
4) Finally, let's build our code in out-of-source manner and run it!
cmake -S . -B build
cmake --build build
./build/helloworld