I have a qt project setup as a subdirs project with my source code in a src directory and unit testing code setup in a test directory. Each has its own project file. I want to be able to compile the source on other computers, but they may not have the googletest library setup. I have looked at the qmake test function "requires()" and "packagesExist()" however, they do not seem to be built to handle external libraries.
How can I instruct qmake to skip the test project if the testing library is not found?
It is not possible without checking typical locations if the library is present in there.
Unfortunately, googletest does not seem to ship package-config ".pc" files either, so that is why you cannot use the packagesExist() qmake function.
So, I would use a bunch of exist call to work this around, or switch away from qmake to something better like cmake.
!exists("/foo/bar/baz.so"):!exists("/hello/world/baz.so"):...: message("Google test is not installed on your system")
If the libraries you're trying to link to do not have pkgconfig information, you can make a qmake config test for each of these libraries using qtCompileTest(). I'll show you here how to use this feature of qmake.
qtCompileTest qmake config tests will run at qmake time. If the test compiles, config_ will be added to the CONFIG variable and qmake will print Checking for <testname>... yes or Checking for <testname>... no depending on whether or not the test compiled.
In your project dir, create a directory with the name config_tests, and under that create a directory for the library or feature you're going to test, a starting simple qmake project and main.cpp file, ending up like so:
myproject/
myproject.pro
<source files, etc>
config_tests/
googletest/
googletest.pro
main.cpp
Make the googletest project be very simple, with just the bare minimum to link an executable to the googletest library, and test including necessary headers for using it. Load this project directly into Qt Creator and test that it actually compiles in the scenarios you expect it to work, and not in others (i.e. test for the various platforms you'll be using that contain and don't contain the googletest library)
Next, use this qmake config test project in your main project by adding the following to the top of your project. load(configure) below loads in the qmake support for qtCompileTest - as it's not normally built-in:
load(configure)
qtCompileTest(googletest)
In the places where you will be compiling features that require googletest, you can wrap them in the following qmake test:
CONFIG(config_googletest) {
}
Related
Using CLion, I have a project structure that looks like this:
You'll see that in the root there are an include directory, a src directory, a lib directory, a cmake-build-debug directory, a CMakeLists.txt file (see red arrow), and a tests directory. The project builds a shared object into lib using the root-level CMakeLists.txt file and the various source, header, and external files.
I can successfully run the root-level CMakeList.txt file and build the library. So far, so good.
Here is the issue. In addition to the above, I am now interested -- on an informal, exploratory basis -- in testing some of the code in the project. To that end, as an initial example, I have created a test_nnls directory with its own CMakeLists.txt (see yellow arrow) file and a test_nnls.cpp file. The code in test_nnls.cpp creates some dummy data, calls a function in src/nnls.cpp, and prints the results. The build process here just creates an executable that does this. This approach is not meant to be part of any formal test framework and I do not want the test to run as part of the root-level build. This is just me adding a simple test program in the overall project that I would like to compile and run on an independent basis when I feel the need. I plan to possibly implement a formal test framework later, but at present I don't know how to do this and for now just need to print some simple output to see if the chosen code is working correctly.
The problem is that I cannot seem to execute the CMakeLists.txt file (yellow arrow) to build the test. It does not appear to be possible in CLion to set up a build for the test program using cmake. How do I structure all of this to get what I want? Thanks.
You don't execute a CMakeLists.txt. It is read by cmake (the root CMaksLists.txt file), which is called by CLion. However, CLion only passes the root CMaksLists.txt file to cmake. Even if you call cmake yourself you would only pass this root CMaksLists.txt file.
If you want to define targets (or anything) in other CMaksLists.txt files located in other folders, then you must add add_subdirectory(folder_name_that_contains_another_CMakeLists_file) to your root CMaksLists.txt file. Only then targets in these other CMaksLists.txt files will appear in CLion.
Note that a few things should appear in the root CMaksLists.txt file, but not in the other ones. Particularly, the two lines below should only be in the root file
cmake_minimum_required(VERSION 3.14) # Choose the minimum cmake version
project(name_of_your_project)
I'm creating a very small project that depends on the following library: https://github.com/CopernicaMarketingSoftware/AMQP-CPP
I'm doing what i always do with third-party libraries: i add their git repo as a submodule, and build them along with my code:
option(COOL_LIBRARY_OPTION ON)
add_subdirectory(deps/cool-library)
include_directories(deps/cool-library/include)
target_link_libraries(${PROJECT_NAME} coollib)
This has worked perfectly for libraries like Bullet, GLFW and others. However, this AMQP library does quite an ugly hack. Their include directory is called include, but in their CMake install() command, they rename it to amqpcpp. And their main header, deps/cool-library/amqpcpp.h, is referencing all other headers using that "fake" directory.
What happens is: when CMake tries to compile my sources which depend on deps/cool-library/amqpcpp.h, it fails because it's not finding deps/cool-library/amqpcpp/*.h, only deps/cool-library/include.
Does anyone have any idea how i can fix this without having to bundle the library into my codebase?
This is not how CMake is supposed to work.
CMake usually builds an entire distributive package of a library once and then installs it to some prefix path. It is then accessible for every other build process on the system by saying "find_package()". This command finds the installed distibution, and all the libs, includes etc. automagically. Whatever weird stuff library implementers did, the resulting distros are more or less alike.
So, in this case you do a lot of unnecessary work by adding includes manually. As you see it can also be unreliable.
What you can do is:
to still have all the dependencies source distributions in submodules (usually people don't bother doing this though)
build and install each dependency package into another (.gitignored) folder within the project or outside by using their own CMakeLists.txt. Let's say with a custom build step in your CMakeLists.txt
use "find_package()" in your CMakeLists.txt when build your application
Two small addition to Drop's answer: If the library set up their install routines correctly, you can use find_package directly on the library's binary tree, skipping the install step. This is mostly useful when you make changes to both the library and the dependent project, as you don't have to run the INSTALL target everytime to make library changes available downstream.
Also, check out the ExternalProject module of CMake which is very convenient for having external dependencies being built automatically as part of your project. The general idea is that you still pull in the library's source as a submodule, but instead of using add_subdirectory to pull the source into your project, you use ExternalProject_Add to build it on its own and then just link against it from your project.
I have a CMake project. It is a crossplatform project developed by a team of developers. Visual Studio and other make files are inside version control for library release and external developers.
Each time a file is added we need to recompile all project files for all platforms. How do I force CMake to generate new project files for all systems at once (if possible from inside CMakeLists.txt, not as command line arguments)?
I think it doesn't make sense for this to be possible within the CMakeLists.txt file. CMake is a makefile generator. Everything in the CMakeLists.txt file is configuring the makefile, and it can also be repurposed to make project files.
If the CMakeLists.txt file could also request to generate a different kind of makefile... it would be different from every other command in the CMakeLists.txt file in that it isn't describing the currently selected makefile.
If I were you I would just make a shell script, or a simple makefile, separate from CMake, which rebuilds each of the project files, by invoking CMake from command line with appropriate parameters.
Is the goal of the versioned CMake produced build scripts to not force developers to install CMake?
In any case: it's best to use the right tool for the right job. CMake is for producing build-files and the little scripting necessary to do so. Use a scripting environment (Bash, cmd.exe) to run CMake as necessary for all your platforms.
This keeps the CMake files clean (and readable, CMake scripting is hard to read) and provides clean separation of concerns.
I have the following situation:
I'm working on an application that depends on a number of third party libs, among them wxwidgets
I build the application for multiple target configurations (x86, arm, Linux, Windows) using Linux as my build host system
Due to the above mentioned multiple target configurations, I have chosen to build those third-party libs from source, using CMake's ExternalProject_Add function.
The third-party libs are built 'on-demand' at a location separate from my application's CMAKE_BINARY_DIR so that I can wipe the build tree for my application without having to rebuild the third-party libs (takes a looooong time).
The location of the third-party libs is different depending on what target configuration I build them for (obviously).
I'm quite new to CMake and the problem I currently face is this:
The source files in my application can't find the wx include files and I need to set the correct linker flags to be able to link my application against wxwidgets.
This seems to be handled by a utility 'wx-config' that provides exactly that info as output when run with either the --cppflags or --libs flag. I can not however, figure out how to catch that output and append it to the include dirs and linked libraries I setup from my CMakeLists.txt files.
So basically what I want is.
Build wxwidgets (if it doesn't exist) for the current target configuration
Run wx-config --cppflags and --libs to find out the correct include dirs and linker flags for the current target configuration
Use the info from step 2 when building targets that are my own application
So far I've tried something like this:
# Set a target-configuration-specific location
set(wxwidgetsTop ${MYPROJECT_EXTERNAL_DIR}/wxwidgets/wxwidgets_${MYPROJECT_CURRENT_TARGET_CFG})
# Build the project
ExternalProject_Add( wxWidgetsExternal
PREFIX ${wxwidgetsTop}
URL ${MYPROJECT_EXTERNAL_DIR}/tarballs/wxWidgets-3.0.2.tar.bz2
SOURCE_DIR ${wxwidgetsTop}/src/wxwidgets
CONFIGURE_COMMAND ${configure_cmdline}
BUILD_COMMAND make -j${MYPROJECT_NCPU}
INSTALL_COMMAND make install
)
# Create a wxwidgets target to be used as a dependency from other code
add_library(wxWidgets IMPORTED STATIC GLOBAL)
add_dependencies(wxWidgets wxWidgetsExternal)
# (non-working) attempt to get the correct include dirs and linker
# flags for wxwidgets
add_custom_command(TARGET wxWidgetsExternal
POST_BUILD
COMMAND ${INSTALL_DIR}/bin/wx-config ARGS --cppflags
COMMENT "Running wx-config"
)
but the above does not provide a way to actually use the result from the custom command to append the cppflags and linker options when building the targets that make up my application.
What is a good way to achieve what I want?
I see three different ways of doing this:
Method 1: use find_package
Use wxWidgets as a standalone requirement for your project, and expect the devs to install it before building your project. In your CMakeLists.txt you will need to call find_package(wxWidgets), like this:
find_package(wxWidgets COMPONENTS net gl core base)
if(wxWidgets_FOUND)
include(${wxWidgets_USE_FILE})
# and for each of your dependent executable/library targets:
target_link_libraries(<YourTarget> ${wxWidgets_LIBRARIES})
endif()
This has the advantage of not rebuilding the lib if you rebuild your project, however it requires some work for your user (they need to handle the installation of wxWidgets by hand) and for you (you need to setup include paths / compile definitions / ... by hand).
Method 2: embed wxWidgets
The second option is to bundle wxWidgets in your repo (svn external or git submodule) and usually (re)write the CMakeLists.txt of this lib to be target-oriented. Then, in your top-most CMakeLists.txt, you can do the following:
# for example, if you just need core and net:
target_link_librairies(my_app PUBLIC wxWidgetsCore wxWidgetsNet)
# No need to manually setup include dirs, etc...
To make a CMakeLists.txt target-oriented, you define include directories and other compilation properties for a target, not a directory. Example:
# When defining wxWidgetsCore, for example
add_library(wxWidgetsCore ...)
target_include_directories(wxWidgetsCore PUBLIC someDir)
target_compile_definitions(wxWidgetsCore PUBLIC -pedantic)
target_link_libraries(wxWidgetsCore PUBLIC someLib)
The drawback of this approach is that rebuilding your project will trigger a rebuild of wxWidgets. However, it is possible to trick this by not using "rebuild" but "clean just my app, then build". Here is some insight on how to achieve this.
Method 3: some sort of hybrid
The big drawback of method 2 leads to the third approach: don't put wxWidgets in your project, but create a CMakeLists.txt that will "import" the lib. The idea: you ask your user for the directory where wxWidgets is installed, then this script will setup everything for your project. First, put the CMakeLists.txt here:
/your-project-root
/thirdparty
/wxWidgets
CMakeLists.txt
/dir-where-wxwidgets-is-installed
...
Now, you define an imported target:
# When defining wxWidgetsCore, for example
set(WX_INCLUDE_DIR ${USER_SPECIFIED_WX_ROOT}/include)
add_library(wxWidgetsCore IMPORTED GLOBAL)
set_property(TARGET wxWidgetsCore APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${WX_INCLUDE_DIR})
See INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_LINK_LIBRARIES. You need your user to have build wxWidgets somewhere in his system, but from your point of view you just do target_link_libraries(your_app PUBLIC wxWidgets...), as in method 2. The advantage is that this approach is interchangeable with method 2 transparently, and you don't put the whole dependency in your project.
Setting cppflags and linker flags has to be done at CMake time, but you are trying to run wx-config at build time and you are not capturing its output anyway, so your add_custom_command() isn't doing anything useful other than printing things to the build tool's output.
Ideally, you would use the FindwxWidgets module CMake already provides. It requires wxWidgets to already be built (but see further below). Have a look at the CMake documentation for it and see if that at least sounds like what you are trying to achieve manually by using wx-config. If you can get FindwxWidgets to do the job for you, that would be a much cleaner approach.
Getting something to build at configure time so you can use it later on in your CMakeLists.txt file is a bit more tricky. ExternalProject_Add() downloads and builds things at build time, but you need wxWidgets to be built earlier at configure time. I wrote an article recently for how to do at least the downloading part at configure time and you should be able to adapt it to do the whole build at configure time instead. The article uses Google Test as its example and can be found here:
https://crascit.com/2015/07/25/cmake-gtest/
It would be trivial to make it put the wxWidgets build wherever you like, not just in the CMAKE_BINARY_DIR area. That would allow you to have different wxWidgets builds for each build configuration and to be able to wipe out your application's build tree independently of the wxWidgets builds.
Hope that points you in the right direction.
The solution I use checks for wxWidgets installation in the system using find_package, if it's not found, then the script downloads wxWidgets from github and links the program against downloaded library. The lib is installed in the build directory, so only the first build is slow - subsequent builds do not even check wxWidgets sources timestamps, so the process is as fast as building using preinstalled wxWidgets library.
Here's how my script does it:
It quietly checks for wxWidgets installation using find_package(wxWidgets QUIET),
If it's found, the script adds a dummy library wxWidgets_external,
If it's not, then it creates an ExternalProject named wxWidgets_external which downloads, builds and installs the library in the build dir, setting wxWidgets_ROOT_DIR to point to the wxWidgets installation dir,
Then we add another ExternalProject pointing to a folder with the main program's source files and CMakeLists.txt build script. This external projects depends on wxWidgets_external which is either a dummy library in case wxWidgets is preinstalled in the system, or an external project set up to download the library from github,
In the aforementioned CMakeLists.txt we again call find_package, this time with REQUIRED parameter and use the library the standard way (https://docs.wxwidgets.org/trunk/overview_cmake.html). Because we set up the dependencies and variables correctly, this call will use either preinstalled wxWidgets (if it's available) or the one downloaded from github.
There are more quirks to it, but that's the gist of it. The full sample code (tested on Linux, Windows and Mac) is available on github (https://github.com/lszl84/wx_cmake_template).
Also see full blog post which explains this in more detail: https://justdevtutorials.medium.com/wxwidgets-cmake-multiplatform-superbuild-4ea86c4e6eda
I am trying to compile a Qt project that uses poppler library for pdf (linux).
I put #include in the mainwindow.cpp
I put poppler folder in my project folder besides mainwindow.cpp
poppler-qt4.h is in poppler-0.16.7/qt4/src
I do not need to recompile poppler, I just need to link the library through its headers but I do not know how to do. If compilation is necessary I can do it, but I tried ./configure and it said "./configure not found".
I searched for other similar threads but they were not enough useful to me.
I know LIBS is involved but makefile is overwritten by Qt-creator?
I'd prefer to learn how to "officially" inform Qt-creator that I want to add the library.
Please can help?
You have a good example, completed with source code, here: Poppler: Displaying PDF files with Qt
Along with including the header files where apropriate, you need to link to the poppler library.
To do so, you need to edit your .pro file and include something like:
INCLUDEPATH += /usr/include/poppler/qt4
LIBS += -L/usr/lib -lpoppler-qt4
These are the "default" paths, you may need to change them accordingly to your particular install location.
EDIT:
From your comments you seem to be trying to build poppler lib from source. The problem is that you're executing ./configure ( make and make install ) in the wrong directory. You "need" to position yourself in the directory where the file configure is located(*). Then execute the traditional commands:
./configure
make
make install
You run configure (you usually have to type ./configure as most
people don't have the current directory in their search path). This
builds a new Makefile.
Type make This builds the program. That is, make would be
executed, it would look for the first target in Makefile and do what
the instructions said. The expected end result would be to build an
executable program.
Now, as root, type make install. This again invokes make, make
finds the target install in Makefile and files the directions to
install the program.
I extracted this quote from http://tldp.org/LDP/LG/current/smith.html. But there are lots of places where you can find more information about these commands. Just google it! :D
(*) You don't really need to be in the same directory as the configure file. But it's easier than writing the full path.