I am building a project with cmake. The project uses the external library plplot; I have configured cmake to the library and headers, and that is cached in variables ${PLPLOT_LIBRARY}, ${PLPLOT_LIB_PATH} and ${PLPLOT_INCLUDE_PATH}. In the plplot library a function has changed name: plwid -> plwidth and I want to detect that. I have written a small try_compile() test:
try_compile(HAVE_PLWID ${CMAKE_BINARY_DIR} cmake/tests/test_plwid.c)
However this test will always fail, because I have to pass header and library information to the try_compile process. Invoking gcc manually like this:
gcc -I${PLPLOT_INCLUDE_PATH} cmake/tests/test_plwid.c -L${PLPLOT_LIB_PATH} -l${PLPLOT_LIBRARY}
works. However I don understand how to pass the necessary flags to the try_compilecommand: I have tried:
try_compile(HAVE_PLWID ${CMAKE_BINARY_DIR} cmake/tests/test_plwid.c
INCLUDE_DIRECTORIES ${PLPLOT_INCLUDE_PATH}
LINK_DIRECTORIES ${PLPLOT_LIB_PATH}
LINK_LIBRARIES ${PLPLOT_LIBRARY})
Then I just get the cmake configure error:
Attempt at a recursive or nested TRY_COMPILE in directory
/path/to/build
I am quite confident the ${PLPLOT_XXX} variables are correct, at least the rest of the build works fine based on these variables.
Update: If I invoke cmakewith the --debug_trycompile command and go to the build/CMakeFiles/CMakeTmp directory and invoke cmakethere manually as:
cmake . -DINCLUDE_DIRECTORIES=/path/plplot/include -DLINK_DIRECTORIES=/path/to/plplot/lib -DLINK_LIBRARIES=plplotd
The test program will build and link correctly; so it seems the challenge is to pass these options correctly to the try_compile() cmake command invocation?
The LINK_DIRECTORIES and INCLUDE_DIRECTORIES cannot be passed as options to try_compile but have to passed as extra flags with the CMAKE_FLAGS option in the following way:
try_compile(HAVE_PLWID "${CMAKE_BINARY_DIR}/temp" "${CMAKE_SOURCE_DIR}/tests/test_plwid.c"
LINK_LIBRARIES ${PLPLOT_LIBRARY}
CMAKE_FLAGS
"-DINCLUDE_DIRECTORIES=${PLPLOT_INCLUDE_PATH}"
"-DLINK_DIRECTORIES=${PLPLOT_LIB_PATH}")
Related
I am using cmake version 3.14.0-rc3 to make my codes. When I target any code written in C or C++ in my CMakelist.txt as follows, it works pretty and makes the executable file.
cmake_minimum_required(VERSION 3.3)
PROJECT (HELLO)
ADD_EXECUTABLE(hello hello_world.cpp)
but while I am trying to make this code with Tcl scripts, it fails and I receive the following fatal error:
Fatal error while making a tcl script with cmake
Can anyone help me to overcome this issue? It seems that cmake is not normally able to compile Tcl scripts.
Thank in advance for your kind replies and helps.
Bests,
Daryon
You have to watch out for a different path, e.g., running custom commands or adding custom targets to your CMake project. You seem to confuse the nature of libraries, executables, and external commands in the context of CMake, I am afraid.
I think there should be a way to execute Tcl scripts with CMake as
well.
You might want to attempt the following: In CMakeLists.txt, you define a custom target MyTarget that calls out to a TCLSH executable, if available:
CMAKE_MINIMUM_REQUIRED(VERSION 3.3)
PROJECT (HELLO)
find_program (TCLSH tclsh)
if (TCLSH)
add_custom_target(
MyTarget ALL
COMMAND TCLSH myScript.tcl
)
endif (TCLSH)
(1) find_program and if/endif will make the custom target only available under the condition that an executable called tclsh was found.
(2) myScript.tcl is a Tcl script in your project directory.
(3) Running cmake . && make will call out to effectively to: tclsh myScript.tcl, producing:
$cmake . && make
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/hello
This is a message written by Tcl scripts
Built target MyTarget
This is just to get you started, you will have to read more about adding commands, targets, or executing sub-processes from within CMake.
The only online resources I have found are the CMake documentation on CMAKE_<LANG>_CPPLINT (link here) and this example (link here), but I cannot figure out how to actually use it inside a CMakeLists.txt file.
I tried the example provided, but I can't make it work. FYI, I installed cpplint as explained here.
As of now, I can run the cpplint python script inside CMakeLists.txt using this CMake command:
execute_process(COMMAND cpplint path/To/File/To/Analyse.cpp)
However, I am pretty sure that this is not the right way to do this.
Recommended way to use static analysis tools with CMake was presented in Daniel Pffeifer's "Effective Cmake" (https://www.youtube.com/watch?v=rLopVhns4Zs&=&t=77m13s).
You can either define it when calling cmake, eg.:
cmake "-DCMAKE_CXX_CPPLINT=cpplint" ..
or put it into CMakeLists.txt:
set(CMAKE_CXX_CPPLINT "cpplint")
Recommended option is the first one (we shouldn't define in a project what isn't a project requirement).
CMake will call cpplint for each file it compiles. You can pass extra arguments after semicolon (e.g. -DCMAKE_CXX_CPPLINT=cpplint;--linelength=100).
Downsides of this method:
Errors count will not get accumulated (because cpplint is invoked for each file separately).
It will not check header files (as opposed to what D. Pffeifer says in his presentation, include files are not being scanned by cpplint).
Note that you can use other static analysis tools the same way:
Clan Tidy "-DCMAKE_CXX_CLANG_TIDY=/usr/bin/clang-tidy-3.9;-checks=*"
CppCheck "-DCMAKE_CXX_CPPCHECK=/usr/bin/cppcheck;--std=c++11"
IWYU "-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=/usr/bin/iwyu;--transitive_includes_only"
LWYU cmake -DCMAKE_LINK_WHAT_YOU_USE=TRUE
clazy
Some of them will require "compilation database" (set(CMAKE_EXPORT_COMPILE_COMMANDS ON)).
I failed to use CMAKE_<LANG>_CPPLINT to check code style.
I make it by using add_custom_target.
download cpplint.py
then download cpplint.cmake or write yourselt.
Suppose that there is a source code directory named src in your project, code those statements into your CMakeLists.txt.
aux_source_directory(${CMAKE_SOURCE_DIR}/src src)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}) #I put cpplint.cmake in $CMAKE_SOURCE_DIR
include(cpplint)
add_style_check_target(phoenix-cpplint "${src}")
Note:
you should pass the whole list, so use "${src}" instead of ${src}.
By default nothing depends on the custom target, see add_custom_target.
If there's still some problem, debug your CMakeLists.txt.
I have been struggling with the same problem.
I tried it with CMake 3.10.2 and the comment by user2449761 is still true. Using set(CMAKE_CXX_CPPLINT "cpplint") still does not check any header files.
The answer by kgbook does not work anymore, since aux_source_directory does not list the header files. You can, however, use
get_target_property(src staticcodecheck SOURCES)
That will give you all the non-system headers. The rest can be kept the same. As for running cpplint at a specific time, you might try
add_custom_command(TARGET ${TARGET}
PRE_BUILD
...
That will replace add_custom_target(${TARGET_NAME}... in his cpplint.cmake.
Hope this helps.
The following is how I am running cpplint on all files in the src directory for a project.
file(GLOB_RECURSE SRC_FILES "${PROJECT_SOURCE_DIR}/src/**/*")
add_custom_command(TARGET target PRE_BUILD COMMAND cpplint ${SRC_FILES})
This runs every time, it fails the build when there are cpplint issues, and it runs on all files in the src directory. You may also want to consider adding cpplint specific arguments to the command, such as --quiet or --extensions for example.
I have two projects using CMake.
The first is a shared library. It compiles and installs fine. Currently, it is still necessary to build 'debug' releases of it. So presently it is installed under ~/localdebug. That folder looks like the root of a filesystem with a 'include' and 'lib' directory. The same concept as '/usr/local'.
The second is a program. It needs to compile and link against my library in ~/localdebug. The CMakeLists.txt file for it looks like this:
cmake_minimum_required(VERSION 2.6)
set(CMAKE_C_FLAGS "-std=gnu99")
#add_definitions(-pg)
find_library(SANDGROUSE_LIB NAMES sandgrouse)
add_library(http_parser http_parser.c)
add_executable(rsva11001adapter main.c rsva11001.c)
target_link_libraries(rsva11001adapter http_parser ${SANDGROUSE_LIB})
I run the following to set up the make files:
cmake --debug-output -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH="/home/ericu/localdebug" ..
Based on the CMake wiki, setting DCMAKE_PREFIX_PATH does exactly what I want.
CMAKE_PREFIX_PATH
(since CMake 2.6.0) This is used when searching for include files, binaries, or libraries using either the FIND_PACKAGE(), FIND_PATH(), FIND_PROGRAM(), or FIND_LIBRARY() commands. For each path in the CMAKE_PREFIX_PATH list, CMake will check "PATH/include" and "PATH" when FIND_PATH() is called, "PATH/bin" and "PATH" when FIND_PROGRAM() is called, and "PATH/lib" and "PATH" when FIND_LIBRARY() is called. See the documentation for FIND_PACKAGE(), FIND_LIBRARY(), FIND_PATH(), and FIND_PROGRAM() for more details.
However, when I do a 'make VERBOSE=1' this is what I get:
cd /home/ericu/rsva11001adapter/build/src && /usr/bin/gcc -std=gnu99 -g -o CMakeFiles/rsva11001adapter.dir/main.c.o -c /home/ericu/rsva11001adapter/src/main.c
/home/ericu/rsva11001adapter/src/main.c:19:31: fatal error: sandgrouse/server.h: No such file or directory
compilation terminated.
So, it does not seem that CMake is finding things in CMAKE_PREFIX_PATH. It obviously is not adding -I variables to the compiler invocations either.
An inspection of CMakeCache.txt makes it seem as though it has no idea what the variable is:
// No help, variable specified on the command line.
CMAKE_PREFIX_PATH:UNINITIALIZED=/home/ericu/localdebug
I've been working on this for over an hour. I'm nearly at the point of giving up using CMake if it is this difficult to use a non-standard library with it.
You should instruct CMake to add -I flags when compiling your library:
find_path(SANDGROUSE_INCLUDE_DIR sandgrouse/server.h)
include_directories(${SANDGROUSE_INCLUDE_DIR}
Place these lines before add_library() invocation.
I'm using CMake 2.8 in order to build an application based on MQX OS (using CodeWarrior).
The CMake project basically builds a set of static libraries (let's say LIB1 and LIB2).
I then reference these libraries in the final executable cmake rule:
target_add_executable(X ${some_sources})
target_link_libraries(X LIB1 LIB2)
My problem is that some symbols are defined in more that one library.
Thus, a link command like:
mwldarm <args> -o <output> <objects> /path/to1/libLIB1.a /path/to2/libLIB2.a
would lead to multiple definition of symbols error.
Instead, I would like CMake to generate a link command like:
mwldarm <args> -o <output> <objects> -L/path/to1 -L/path/to2 -lLIB -lLIB2
Question: How to get the following variables from CMAKE?
Libraries directories flags (ex: -L/path/to1 -L/path/to2)
Libraries link flags (ex: -lLIB -lLIB2)
I've read stuff concerning RPATH but it seems to concern shared libraries only. Am I right?
Thanks for advance.
I do appreciate.
It seems that policy CMP0003 may be what you need.
To use it add the following line near the beginning of your CMakeLists.txt:
CMAKE_POLICY( SET CMP0003 OLD )
Another possibility is to directly set the dependencies and search path, however it's not the cleanest way. Assuming you libraries are called liba.a and libb.a, then:
LINK_DIRECTORIES( ${paths_to_search_for} )
TARGET_ADD_EXECUTABLE(X ${some_sources} )
ADD_DEPENDENCIES(X LIB1 LIB2)
TARGET_LINK_LIBRARIES(X a b )
Note that in this case a and b are not cmake targets, therefore a little machinery is needed to correctly set the dependencies.
Part of the design of CMake is that it links with full paths. Why is that a problem?
Toggling the behavior with the policy is not the correct approach.
http://www.cmake.org/gitweb?p=cmake.git;a=commitdiff;h=cd4fa896b
I think CMP0003 is used to switch on/off the function of adding searching path automatically as described in the official document
Libraries linked via full path no longer produce linker search paths.
rather than about replacing the path name with -l.
When linking a library, if the library is a target CMake known, CMake always replaces related -L and -l options with the library's path name. This may not be a problem for linking static libraries. But for a executable to link a shared library, it's may be a problem. Then I found a hacking method, code like below, to solve the problem linking a shread library using -L and `-l' rather than absolute path.
# Find out the link.txt
set(LINK_TXT "${CMAKE_BINARY_DIR}/${ToLinkLib}/CMakeFiles/${ToLinkLIb}.dir/link.txt")
# Add the searching path into link command
add_custom_command(TARGET ${YourTarget} PRE_BUILD
COMMAND sed ARGS -ie "\"s;[[:blank:]]-l; -L${LIBRARY_OUTPUT_PATH} -l;\"" ${LINK_TXT}
DEPENDS ${LINK_TXT}
COMMENT "Hacking CMake: edit __link.txt__ to use -l instead of path to link internal library ...")
# NOTE: Dont't missing the `-l'.
target_link_libraries(${YourTarget} -l${ToLinkLib})
Of course, this is just a hacking so may not be working well with all versions of CMake.
UPDATED: why linking a shared library may be a problem?
When I run a executable cross compiled for android, which linking a shared library built by the same CMake scripts, I've encounter a problem of linking failed. After I used the above hacking method to get a new version, I can run my executable with a command like below
$ LD_LIBRARY_PATH=. ./the_exe opts
I have the following directory layout:
main_folder
+ static_lib1
+ executable
Both 'static_lib1' and 'executable' have a full CMakeLists so that they can be
built independently.
The 'executable' depends on 'static_lib1'. It uses find_package() to locate 'static_lib1'.
The main_folder contains a CMakeLists that includes both 'static_lib1' and 'executable' via add_subdirectory for conveniently building the whole project in one go.
Everything works fine if I manually build 'static_lib1' and then 'executable'. But when running the CMakeLists from the main folder, I get an error because find_package is unable to find the library files from 'static_lib1' which have not yet been built.
How can I resolve this while keeping the CMakeLists files separate (i.e. without including the static_lib's CMakeLists from the executable's CMakeLists)?
In executable's CMakeLists.txt you can check if you are building stand-alone or as part of project:
if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
# stand-alone build
find_package(static_lib1)
else()
include_directories(../static_lib1)
link_directories(../static_lib1)
...
target_link_libraries(executable static_lib1)
endif()
Switch from a file-based approach to a target-based approach for handling the dependency from executable to static_lib1.
The original problem occurred because executable called find_package for locating static_lib1, which then attempted to fill a variable like STATIC_LIB1_LIBRARY with the paths to the library files by calling find_library. executable then consumes the content of that variable in a target_link_libraries(executable ${STATIC_LIB1_LIBRARY}) call. The problem here is, since those library files only get generated as part of the build, that call to find_library will not be able to find anything.
Building executable needs to support two scenarios here:
Building standalone, where a pre-compiled version of static_lib1 is located somewhere on the disc.
Building from main_folder, where both executable and static_lib1 are part of the same build.
The approach from the question supports scenario 1, but not scenario 2.
Instead of using using a variable to communicate a dependency between the two builds, use a target. The CMakeLists.txt for static_lib1 likely creates a library target like add_library(static_lib1 [...]). In executable we now simply do target_link_libraries(executable PUBLIC static_lib1). This is sufficient to support scenario 2.
To also allow for scenario 1 at the same time, we look at the call to find_package(static_lib1) in the CMakeLists.txt for executable. Instead of providing a variable like before, this call now needs to provide a target static_lib1 for consumption.
So we adapt the find script for static_lib1 to the following behavior:
If a target static_lib1 already exists, there's nothing to be done and the find script can just return (this is scenario 2).
Otherwise, we call find_library to locate the library file on disc (as before in the original approach) and then create a new imported target: add_library(static_lib1 STATIC IMPORTED). We then configure all relevant properties of the static library to that target. For instance, to add the location of the library file, we could do
set_target_properties(static_lib1 PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
IMPORTED_LOCATION ${STATIC_LIB1_LIBRARY}
)
To support multi-config generators like MSVC, instead of setting IMPORTED_LOCATION and IMPORTED_LINK_INTERFACE_LANGUAGES, you will want to set the configuration specific properties like IMPORTED_LOCATION_DEBUG and IMPORTED_LOCATION_RELEASE instead. Since this can get quite tedious to do manually, you can have CMake generate this information (and a bunch of other convenient stuff) for you in a package script. The find mechanism for package scripts works slightly different under the hood, but the code in the CMakeLists.txt for executable will look just the same, a simple call to find_package(static_lib1). The main difference is that this call will then not dispatch to a hand-written find script, but to a package script that was automatically generated by CMake as part of the build process of static_lib1.
I guess I will leave this answer for posterity since only recently I have searched for a solution to this problem and found out that...
Since CMake 3.24 it is possible!
It is possible to override subsequent calls to find_package() with FetchContent_Declare() flag OVERRIDE_FIND_PACKAGE.
Your
add_subdirectory("path/to/static_lib1")
call has to be replaced in main_folder/CMakeLists.txt with:
include(FetchContent)
FetchContent_Declare(
static_lib1
SOURCE_DIR "path/to/static_lib1"
OVERRIDE_FIND_PACKAGE
)
Any calls to find_package(static_lib1) will call FetchContent_MakeAvailable() for you, virtually making it identical to add_subdirectory() call.
You can read more about OVERRIDE_FIND_PACKAGE in CMake documentation.