How to tell CMake to use during compilation specific version of Qt? - c++

There are two versions of Qt installed on my Ubuntu - 5.2 (default) and 5.4 (in /opt/Qt/5.4/gcc_64):
CMakeLists.txt:
project(testproject)
find_package(Qt5Core HINTS /opt/Qt/5.4/gcc_64 REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main Qt5::Core)
main.cpp:
#include <QDebug>
int main()
{
qDebug() << "runtime version: " << qVersion() << " compiled with: " << QT_VERSION_STR << endl;
return 0;
}
Running the program:
cmake . && make clean && make && LD_LIBRARY_PATH=/opt/Qt/5.4/gcc_64/lib ./main
Output:
runtime version: 5.4.0 compiled with: 5.2.1
How to tell inside CMake to use Qt 5.4 instead of default Qt 5.2? I've tried several options for HINTS in find_package but none of them looks to work.

I took a look through the CMake files generated by an installation of Qt5, and no where in those files are hints being ingested from the caller. These CMake files all use relative paths once one of them is picked up.
That is, if you're looking for the core library, then all of the dependencies that version of the core library will be the correct version. So the goal is to get it to pick the right CMake module when you call find_package, and there are a couple of ways to do that using CMake level hints.
Export CMAKE_PREFIX_PATH
You can set the prefix path to the base directory your Qt is installed to. The base directory is the directory containing lib/ and bin/. In your case, this might be something like this:
export CMAKE_PREFIX_PATH=/opt/Qt/5.4/gcc_64:$CMAKE_PREFIX_PATH
and then from the same shell session run your cmake commands.
Set Qt5Core_DIR in your CMakeLists.txt
This requires setting a variable that points to the right CMake root module you want your Qt to be found from:
set(Qt5Core_DIR /opt/Qt/5.4/gcc_64/lib/cmake/Qt5Core)
find_package(Qt5Core REQUIRED)
Of course, the issue with this is that if you wanted to find another module, you'd have to set the specific Qt5<MODULE>_DIR variable before your find_package call.

Related

CMake find specific package of multiple packages with different versions (NCurses)

I currently have a CMake file that finds and links a library (NCurses) to another library
...
set(CURSES_NEED_NCURSES TRUE)
find_package(Curses REQUIRED)
include_directories(${CURSES_INCLUDE_DIR})
add_library(myLibrary STATIC ${sources})
target_link_libraries(myLibrary ${CURSES_LIBRARIES})
target_compile_options(myLibrary PUBLIC -std=c++20 -Wall -Wconversion)
...
This works fine, however unfortunately it is pulling up a different version than I need (5.7 instead of 6.1)
#include <ncurses.h>
#include <iostream>
int main()
{
std::cout << "VERSION: " << NCURSES_VERSION;
}
outputs: VERSION: 5.7
I do have the desired package installed under: /usr/local/ncurses/6_1.
But the logs seem to say it is pulling it from a different location: Found Curses: /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk/usr/lib/libncurses.tbd
How can I specify which of these I want to use?
Okay I have figured this out, to anyone else who might come across this.
First I installed the latest version of ncurses (6.3) from here: https://invisible-island.net/ncurses/#downloads-h2
(I downloaded the gzipped tar)
I then went through and deleted all references in my usr/local i could find to ncurses.
I then extracted the tar, and entered the new directory.
I ran just plain ./configure inside the directory (with no flags).
After that finished, I ran make
Then I ran make install, after removing symlinks to stop collisions, make install was able to run properly.
Ensure that the CMake variable CURSES_NEED_NCURSES is set to TRUE before finding the package:
set(CURSES_NEED_NCURSES TRUE)
find_package(Curses REQUIRED)
and it will work perfectly :)

CLion Not Finding GLUT with CMake

I have a problem that I can't seem to find the settings to modify.
When attempting to find the GLUT package using CLion's CMake utilities on Ubuntu, it does not find GLUT. Using command-line CMake and Makefile commands, however, finds the dependencies perfectly and allows the following to generate and compile:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(mre)
set(CMAKE_CXX_STANDARD 20)
find_package(OpenGL REQUIRED) # Works in CLion and terminal
find_package(GLUT REQUIRED) # Works only in terminal
include_directories(GL)
add_executable(mre mre.cpp)
target_link_libraries(mre -lglut -lGLU -lGL)
// mre.cpp
#include <GL/gl.h>
#include <GL/glut.h>
int main()
{
return 0;
}
Whereas attempting to use these files in a CLion project would cause errors (first unable to find GLUT, mitigated by manually setting library and include variables; then GL/glut.h: No such file or directory, which I am unable to fix).
Does anyone have any suggestions? I'm assuming it's something to do with a working directory or prefixes, but CMAKE_PREFIX_PATH is unset in CLion, and setting it to various values does nothing to solve the problem.
Thanks!
You know something has gone wrong when you write include_directories or -l flags by hand. You should absolutely always link to libraries via their imported targets.
See the documentation:
OpenGL package: https://cmake.org/cmake/help/latest/module/FindOpenGL.html
GLUT package: https://cmake.org/cmake/help/latest/module/FindGLUT.html
Try this revision:
cmake_minimum_required(VERSION 3.16)
project(mre)
find_package(OpenGL REQUIRED)
find_package(GLUT REQUIRED)
add_executable(mre mre.cpp)
target_link_libraries(mre PRIVATE OpenGL::GL OpenGL::GLU GLUT::GLUT)
target_compile_features(mre PRIVATE cxx_std_20)
As for not being able to find GLUT... just set CMAKE_PREFIX_PATH in CLion's settings to whichever directory on your system contains include/GL/glut.h.
Alternative solution
CLion was installed through the Software Center via Flatpak, which uses some kind of filesystem sandboxing that may be interfering with paths. I tried explicitly allowing /usr and related paths, but had no effect.
I have reinstalled via JetBrains's official archive, which correctly detects GLUT and OpenGL. Their official snap also works properly.

Using SDL2 with CMake in CLion

After hours of scouring the web and SO for a solution I'm at a standstill. Nothing has worked so far for me...
I'm on Windows, using CLion IDE which uses CMake. My goal is to correctly link SDL2 to my project and use it through #include "SDL.h" which is the correct way.
The format of my CMakeLists.txt file
Specifics regarding the directory where I should have put the MingW development library of SDL2
Any requirements regarding windows ENV variables that I might have to set.
My CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.6)
project(sdl2Project)
set(CMAKE_CXX_STANDARD 11)
#This is where sdl2-config.cmake is located
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "C:/Users/MyUserName/CLibraries/SDL2-2.0.5/x86_64-w64-mingw32/lib/cmake/SDL2")
set(SOURCE_FILES main.cpp)
add_executable(sdl2Project ${SOURCE_FILES})
find_package(sdl2 REQUIRED)
target_include_directories(sdl2Project PUBLIC ${SDL2_INCLUDE_DIRS})
target_link_libraries(sdl2Project ${SDL2_LIBRARIES})
There is no FindSDL2.cmake file used.
The SDL2 library I downloaded from libsdl.org is located in:
C:/Users/MyUserName/CLibraries/SDL2-2.0.5/x86_64-w64-mingw32
I have no experience with CMake so I'm unable to truly understand where the problem stems from. What are the steps I need to take in order for it to find the library and link it correctly??
EDIT:
My Project structure is the following:
sdl2Project
cmake-build-debug
CMakeLists.txt
main.cpp
Looking in your FindSDL2.cmake, you need to provide an hint to CMake about where the library is installed. You could do this by setting an environment variable SDLDIR, but you shouldn't. General advice: you shouldn't use a CMake package that wasn't provided with the sources you're using.
Looking in sources of SDL2, root directory contains a file sdl2-config.cmake.in that should have been configured and installed in your install directory as sdl2-config.cmake: that's the package file you should use.
Am I right guessing the file C:/Users/MyUserName/CLibraries/SDL2-2.0.5/sdl2-config.cmake exists?
If yes, to allow CMake to find it, add your install directory to CMAKE_PREFIX_PATH, before calling find_package:
set(CMAKE_PREFIX_PATH
${CMAKE_PREFIX_PATH}
"C:/Users/MyUserName/CLibraries/SDL2-2.0.5"
)
find_package(sdl2 REQUIRED)
Note the use of "/" in the path instead of "\" which could be interpreted as escaping character. Quotes around the path are only necessary if the path contains whitespaces.
EDIT:
Moreover, you misused target_link_libraries with a wrong target: SDL2 which you don't build in your project, instead of sdl2Project.
You also used a wrong variable: SDL2_LIBRARY instead of SDL2_LIBRARIES; you can see the good variable name by looking in sdl2-config.cmake.
You may consider target_include_directories instead of include_directories, but again the variable name you used is wrong: SDL2_INCLUDE_DIR instead of SDL2_INCLUDE_DIRS.
Try:
target_include_directories(sdl2Project PUBLIC ${SDL2_INCLUDE_DIRS})
target_link_libraries(sdl2Project ${SDL2_LIBRARIES})

Setup Boost in Clion

How to use Boost library in Clion with MinGW ? I have downloaded and unzipped boost_1_60_0.zip to C:\boost_1_60_0. What am I supposed to do now ? Do I have to install something ? Here is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.3)
project(server_client)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -s -O3")
set(CMAKE_EXE_LINKER_FLAGS -static)
set(BOOST_ROOT "C:/boost_1_60_0")
set(BOOSTROOT "C:/boost_1_60_0")
find_package(Boost 1.60.0)
if(NOT Boost_FOUND)
message(FATAL_ERROR "Could not find boost!")
endif()
set(SOURCE_FILES chat_server.cpp)
add_executable(server_client ${SOURCE_FILES})
Can not find Boost:
I use MinGW distro by Stephan T. Lavavej with Boost libraries prebuilt.
In my cmaklist.txt I added this
set(Boost_INCLUDE_DIR c:/mingw/include/)
set(Boost_LIBRARY_DIR c:/mingw/lib/)
find_package(Boost COMPONENTS system filesystem REQUIRED)
include_directories(${Boost_INCLUDE_DIR})
This post help me get it going. How to include external library (boost) into CLion C++ project with CMake?
Here's example project for CLion that uses Boost's regex library. It references to this tutorial.
Goal: with CLion create .exe that process jayne.txt as shown in Boost's tutorial.
My example revolves around building Boost Library Binary with GCC, configuring project in CLion and using CMake. It's quite expressive, maybe even an overkill, but I believe you can adapt. On the other hand I'll try to make project itself as system independent as its possible.
Configuration:
OS: Windows 8.1
CLion: 2018.2.4
Boost: 1.68.0
compiler: GCC-6.3.0 (provided by MinGW)
MinGW was configured according to its instructions and JetBrains's suggestions. (I downloaded setup for MinGW 14/10/2018 if that matters.)
A word about tools structure
I decided to create following structure for Boost and things aroung it:
D:\
SDK\
boost\
boost_1_68_0\ # untouched Boost root
boost\
rst.css
...other directories and files...
1_68_0\
build\ # dir for Boost.Build, b2.exe
buildDir\ # intermediate dir for creating libraries
stageDir\ # dir for libraries
lib\
MinGW\
bin\
...other directories...
I left Boost root untouched -- I didn't create any additional directories. This separates Boost sources from created tools and libraries so I can show how to specify these directories explicitly.
Obtain Boost Library Binary
I decided to build libraries from source with GCC.
Download and unpack Boost ("D:\SDK\boost\boost_1_68_0");
Build libraries (5.2):
Open command prompt at \tools\build of Boost root ("D:\SDK\boost\boost_1_68_0\tools\build")
Run bootstrap.bat
Run b2 install --prefix="D:\SDK\boost\1_68_0\build" --toolset=gcc-6.3.0. This creates b2.exe under "D:\SDK\boost\1_68_0\build\bin"
Move command prompt to Boost root (cd "D:\SDK\boost\boost_1_68_0")
(You can consider using "D:\SDK\boost\1_68_0\build\bin\b2.exe --show-directories". It's worth to specify libraries to build (--with-library-name) in the following command, because this step can take a while.) Run "D:\SDK\boost\1_68_0\build\bin\b2" --build-dir="D:\SDK\boost\1_68_0\buildDir" toolset=gcc-6.3.0 --build-type=complete stage --stagedir="D:\SDK\boost\1_68_0\stageDir" --with-regex. It creates following files under D:\SDK\boost\1_68_0\stageDir\lib directory:
libboost_regex-mgw63-mt-d-x32-1_68.a
libboost_regex-mgw63-mt-d-x32-1_68.dll
libboost_regex-mgw63-mt-d-x32-1_68.dll.a
libboost_regex-mgw63-mt-sd-x32-1_68.a
libboost_regex-mgw63-mt-s-x32-1_68.a
libboost_regex-mgw63-mt-x32-1_68.a
libboost_regex-mgw63-mt-x32-1_68.dll
libboost_regex-mgw63-mt-x32-1_68.dll.a
CMake looks for files with specific names in library folder, so be sure to (copy and) change name for one of .a files there. For this example, I changed libboost_regex-mgw63-mt-x32-1_68.a to boost_regex.a.
Create CLion project
Create a new project (for this example its name is CLionBoostRegex) and put content to main.cpp (6):
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main()
{
std::string line;
boost::regex pat( "^Subject: (Re: |Aw: )*(.*)" );
while (std::cin)
{
std::getline(std::cin, line);
boost::smatch matches;
if (boost::regex_match(line, matches, pat))
std::cout << matches[2] << std::endl;
}
}
Configure CLion
Go to (on Windows) File -> Settings -> Build, Execution, Deployment -> CMake, and in CMake options add path to Boost root directory with -DBOOST_ROOT=, i.e.: -DBOOST_ROOT="D:\SDK\boost\boost_1_68_0". If directory with built libraries is placed outside Boost root, add it with -DBOOST_LIBRARYDIR=, i.e.: -DBOOST_LIBRARYDIR="D:\SDK\boost\1_68_0\stageDir\lib". Commands are space separated.
Decide if you want static or dynamic linking.
Option 1: Static linking
For static linking your CMakeLists.txt should look like this:
cmake_minimum_required(VERSION 3.12)
project(CLionBoostRegex)
set(CMAKE_CXX_STANDARD 98)
find_package(Boost REQUIRED COMPONENTS regex)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(CLionBoostRegex main.cpp)
target_link_libraries(CLionBoostRegex -static)
target_link_libraries(CLionBoostRegex ${Boost_LIBRARIES})
Option 2: Dynamic linking
CMakeLists.txt should look like for static linking, but remove target_link_libraries(CLionBoostRegex -static) line.
After building your project make sure to copy .dll library to directory with executable (libboost_regex-mgw63-mt-x32-1_68.dll) along with libstdc++-6.dll from MinGW\bin directory (D:\SDK\MinGW\bin) (or consider including target_link_libraries(CLionBoostRegex -static-libstdc++) line in CMakeLists.txt or add -DCMAKE_CXX_FLAGS="-static-libstdc++" to CMake options in settings).
Run your program (6.4)
Build your target (it creates cmake-build-debug\ directory with default config) (if you picked dynamic linking make sure to add necessary .dlls)
In directory with your executable create jayne.txt file with following content:
To: George Shmidlap
From: Rita Marlowe
Subject: Will Success Spoil Rock Hunter?
---
See subject.
Open command prompt there
Run CLionBoostRegex.exe < jayne.txt
Program should output Will Success Spoil Rock Hunter? as shown in tutorial.
Notes
Changing name for an .a library and choosing -static linking causes the least effort afterwards - you won't have to copy any additional libraries at the price of bigger executable size. When executable size is more important, you can change name for .dll library in Boost libraries directory instead and then copy missing .dlls for your .exe (i.e.: libboost_regex-mgw63-mt-x32-1_68.dll and libstdc++-6.dll).
You can include set(Boost_DEBUG ON) line in your CMakeLists.txt or -DBoost_DEBUG=1 to CMake options to get some precious info.
I used other questions to write this post, most notably: 1, 2, 3, 4.

CMake find_package() cannot find include dirs

I am trying to install two projects: Foo and NeedsFoo. I have successfully compiled and locally installed Foo using cmake. However, I'm on a server and cmake doesn't appear to "remember" where Foo is.
In the cmake to configure NeedsFoo I have
list(APPEND CMAKE_MODULE_PATH "<prefix>/foo-install/CMake/FOO") # add path to FOOConfig.cmake
find_package(FOO REQUIRED)
if( FOO_FOUND )
MESSAGE(STATUS "Found FOO!")
endif( FOO_FOUND )
MESSAGE(STATUS ${FOO_INCLUDE_DIRS})
"Found Foo!" is printed --- so cmake finds FOO --- but the variable ${FOO_INCLUDE_DIRS} is empty and, therefore, the package does not compile. Any thoughts?
EDIT: There seems to be another copy of Foo installed on the server. Unfortunately, I can't use it (it is the 'master' branch of our project and I need to use my own branch). I tried changing the find_package call to
find_package(FOO REQUIRED PATHS "<prefix>/foo-install/CMake/Foo" NO_DEFAULT_PATH)
but that did not solve the problem.
Make sure the headers are installed, often you'll need to install a -dev or -devel package to get the headers. If they are installed and you can see them in your system, they might be on a path that cmake isn't expecting. Open the findFoo.cmake file (on Linux this will generally be in /usr/share/c make-x.y/modules) and check the list of expected locations, see if you're have installed in a less conventional one.