简体   繁体   中英

CMake for external library in C++/Qt project

I'm trying to build a small C++/Qt test program for reading files of various encodings and I am trying to use the Compact Encoding Detection (CED) library from Google: https://github.com/google/compact_enc_det There are many similar questions, but none of them seem to work or reflect my problems.

CED is building fine as an independent project, but I'm struggling to incorporate it as an external library to my project. I'm used to QMake, working in QtCreator, but this will only work with CMake so I started looking around but I'm a bit lost (QMake seems a lot simpler in that regard).

I managed to get my C++/Qt project working with CMake under QtCreator, and also managed to build and test CED (CMake then produces a library: libced.a).

Here is my small (working) CMakeLists file:

cmake_minimum_required(VERSION 3.1.0)

project(FileTestCMakeCED)

set(CMAKE_AUTOMOC ON)

find_package(Qt5 COMPONENTS Core Widgets REQUIRED)

set(FileTest_src
    ${CMAKE_CURRENT_LIST_DIR}/src/mainwindow.cpp
    ${CMAKE_CURRENT_LIST_DIR}/src/main.cpp
)

add_executable(${PROJECT_NAME} ${FileTest_src})

# Use the Widgets module from Qt 5
target_link_libraries(${PROJECT_NAME} Qt5::Widgets)

I'm not pasting CED's CMakeLists, it's a bit longer and it's on the GitHub page: https://github.com/google/compact_enc_det/blob/master/CMakeLists.txt

I would like to either just use CED as a static library (but I tried many ways and none of them worked) or incorporate the sources to have them compile along my project when needed (I've tried linking CED as an external project outside of my source tree, but I could move it in the same source tree if it's easier).

One promising thing I tried was this:

include_directories(../compact_enc_det)
add_library(ced STATIC IMPORTED)
set_target_properties(ced PROPERTIES IMPORTED_LOCATION ../compact_enc_det/lib/libced.a)
...
target_link_libraries(${PROJECT_NAME} Qt5::Widgets ced)

But I get a " no rule to make target.../libced.a " error, even though I just want to use the precompiled library.

The only thing I managed to get working is to start from the CED project made by Google and paste my sources in there and have CED's CMakeLists generate an extra executable for my program, but it's kind of the opposite of what I would like in terms of code and project structure. If I try the other way around (including CED into my project), I always run into path problems for the sources and includes of CED.

Can someone enlighten me as to what the best practice is for this kind of problem? Also, as I said, I'm new to CMake, so a light solution would be appreciated. I'm on Debian Stretch if that matters.

Thanks very much,

One quick solution is to give full path to the libced.a library:

target_link_libraries(${PROJECT_NAME} Qt5::Widgets /path/to/libced.a)

The drawback of this approach is that your CMakeLists.txt has become specific to the machine that you are working on right now. If you distribute your code, other people will not be able to configure their build without changing the source code CMakeLists.txt .

Generally, external libraries are located in CMake using find_package() . For this function to work the package you are trying to link to must provide either a <package>Config.cmake or a Find<package>.cmake file somewhere CMake can find it. These files are already present for many popular packages in your CMake installation (look under /usr/lib/cmake, for example). But writing your own may be a non-trivial solution if you are just starting with CMake because in these files you try to write a script that does many system dependent checks to locate the package and set appropriate variables that can be used further in the build process. You can read about it more on the linked documentation page.

Another solution is to use find_library() where you can provide a hint or environment variable for the location of the required library. If the library is not found, you can print a message or error that asks the user to set a particular hint variable which your CMakeLists.txt can use to locate the library. For example, in your CMakeLists.txt you can do

find_library(CED_LIBRARY ced HINTS ${CED_ROOT})
if( ${CED_LIBRARY} STREQUAL "CED_LIBRARY-NOTFOUND")
    message("Please set CED_LIBRARY variable to location of libced")
endif()

[code edited with two small fixes]

The above snippet instructs CMake to find the file path to a library ced and store the path in CED_LIBRARY variable. If file is not found it will store CED_LIBRARY-NOTFOUND in that variable. If the library is found then you can link with it using

target_link_libraries(${PROJECT_NAME} Qt5::Widgets ${CED_LIBRARY})

find_library() is smart enough to try various prefixes and suffixes on its own so you don't need to write libced . For example, on Windows it may try to find libced.dll , for a shared library on Unix it will search for libced.so etc.

It has been a long time since the question was posted but I am leaving this one just for reference. I have a blog post describing step-by-step almost what you (or anyone else) were trying to do. Please check here: https://michae9.wordpress.com/2022/09/01/shared-lib-to-be-used-by-client-programs-with-cmake/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM