Building MacOSX Frameworks with CMake - cmake

I am trying to build an OS X library using CMake. This libary also includes some amount of resource files (.pdfs used as icon images). In my initial attempts, I have been building the library and the resource files separately as libGeneric.a and generic-Resources.bundle - with, the bundle hosting all the relevant images that libGeneric.a uses.
set (SRC srcfile1.m srcfile2.m)
set (HEADERS srcfile1.h srcfile2.h)
set (ICONS icon1.pdf icon2.pdf)
set (SOURCE_FILE_PROPERTIES ${ICONS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
add_library(generic ${SRC} ${HEADERS})
add_library(generic-Resources MODULE ${ICONS})
set_target_properties(generic-Resources PROPERTIES LINKER_LANGUAGE C) # to suppress CMake error of not able to determine linker language for libary
set_target_properties(generic-Resources PROPERTIES BUNDLE TRUE)
This worked fine, except, I was not able to figure out how to directly include the .bundle in the build process of applications that was using libGeneric.a. The only way I could get CMake to load the bundle was to add it as a source file in the target application. But, since, the bundle had not yet been compiled while running CMake, it would complain that the source file did not exist. As a workaround, I resorted to manually adding the .bundle into xcode after CMake generated the App.xcodeproj file (and I actually compiled the bundle). As this was getting to be cumbersome, I figured I'd try to build a Mac OS X framework instead (to house both the library and the code)
set (SRC srcfile1.m srcfile2.m)
set (HEADERS srcfile1.h srcfile2.h)
set (ICONS icon1.pdf icon2.pdf)
set (SOURCE_FILE_PROPERTIES ${ICONS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
add_library(generic SHARED ${SRC} ${HEADERS} ${ICONS})
set_target_properties(generic PROPERTIES FRAMEWORK TRUE)
set_target_properties(generic PROPERTIES MACOSX_RPATH TRUE) #to suppress cmake warnings on rpath
However, this is creating a framework with just the Icons inside a Resources directory. The code library is missing. I would appreciate some assistance in getting this framework to build correctly. How, do I
get CMake to actually build a library with the indicated source file
and place it inside the framework
get CMake to copy the headers appropriately in the framework.
I am just setting rpath to true now, as I haven't really figured out what to actually do with it. What do I set this to? The objective is to build a private framework, that I would then bundle automatically with my application.
Alternatively, is there an easy way to get CMake to build the bundle file created in my earlier process, and then load that built file into my applications build process.

Related

Using FetchContent with interdependent libraries yields "prefixed in the build directory" error

Consider the following: I have a project which depends on libwebsockets which is itself dependends on mbedtls. I pull everything in from github using FetchContent, which establishes the dependencies in the build folder (_deps).
As I want to build everything statically, I thought I might do libwebsockets a favor and setup CMAKE_PREFIX_PATH so that its find_path() calls will find mbedtls, so libwebsockets knows the path to mbedtls and can see its include files. At the same time I have set cache variables that libwebsockets uses in its find_library() calls variables to the targets in mbedtls, so they are always found even at configure time. More specifically, this is what libwebsocket does:
find_path(LWS_MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h)
find_library(MBEDTLS_LIBRARY mbedtls)
find_library(MBEDX509_LIBRARY mbedx509)
find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
So libwebsockets finds mbedtls in the build directory, everything good so far, but then I get this nasty error still at configure time:
CMake Error in build/_deps/libwebsockets-src/lib/CMakeLists.txt:
Target "websockets" INTERFACE_INCLUDE_DIRECTORIES property contains path:
"C:/dev/realtime-cpp/build/_deps/mbedtls-build/include"
which is prefixed in the build directory.
There are similar errors for the other targets. I understand that the include files are in the build directory. However I don't understand why this is a problem and what I should do instead?

Static library built with CMake as .a with Emscripten instead of .wasm + .js

TL;DR
How do I configure CMake and Emscripten to build my static library to produce a WASM and JS bootstrap file?
I have a static library being built with CMake that I want to build as a WASM library (and JS bootstrap) using Emscripten. Simply using the Emscripten CMake toolchain and adding the appropriate compiler/linker flags result in only a .a file being built - even if -o <project name>.js is added to the compiler and/or linker flags.
The reason is that because I've told CMake I want a static library, it uses CMAKE_AR to build. CMAKE_AR (if undefined) is defined as emar in the Emscripten toolchain file, and emar cannot produce .wasm and .js output.
I have tried creating a new executable target that has a dependency on the library, and otherwise just sets up the compiler/linker settings. However this causes a CMake error, because I've defined an executable target that has no source files (they're associated with the library target). If I add a stub main file, I get an Emscripten warning:
system_libs:WARNING: main() is in the input files, but "_main" is not in EXPORTED_FUNCTIONS, which means it may be eliminated as dead code. Export it if you want main() to run.
I could get round by adding an empty file to exe source file list (probably, I haven't tried), but this feels very much like a hack.
You are correct in that you need to create an executable target in order to produce a .wasm file.
If cmake insists on you creating a dummy source file because it doesn't understand that all the code for your program can come from libraries then I guess you that is your best option.
See CMake: Is it possible to build an executable from only static libraries and no source? for how to work around this limitation of cmake.

CMake library file missing

I'm currently struggling with cmake.
I'm using Cmake for an embedded platform with GCC.
My project is separate into several modules. Each module is build into a static library. At link time, all of these libraries are collected and linked into one binary.
The problem: I created a new folder for some unit tests. All sources are build into a library libunit_tests.a.(I checked the library actually gets created).
However in my linker call other libraries are passed to the linker, mine however gets omitted resulting in an undefined reference error.
My folder structure looks like this
*
unit_tests/
*
unit_tests/inc
*unit_tests/src
There is one Cmake file located at
- /unit_tests/CMakeLists.txt
My actual CMakeLists.txt file is pretty basic
include_directories("./inc")
set(module_name "unit_tests")
set(MODULE_SOURCES
./inc/active_tests.h
./inc/Run_All_Tests.h ./src/Run_All_Tests.c
)
###########################
# add library
###########################
if(MODULE_SOURCES)
# add files to library
add_library("${module_name}"
${MODULE_SOURCES})
target_link_libraries("${module_name}"
-Wl,--start-group
-Wl,--end-group)
endif()
How do i pass this library to the linker to resolve the undefined reference error?
I thought this is done via add_libary and target_link_libraries?

CMake package configuration files for upstream projects using Qt5 problems

I am working on a larger C++ library that is using CMake and depends on Qt.
We moved from Qt4 to Qt5 and now I encounter a problem when using our lib
in an upstream project. As a minimal working example demonstrating the problem please have a look at this repo:
https://github.com/philthiel/cmake_qt5_upstream
It contains two separate CMake projects:
MyLIB: a tiny library that uses QString from Qt5::Core.
It generates and installs package configuration files
MyLIBConfig.cmake, MyLIBConfigVersion.cmake, and MyLIBTargets.cmake
in order to be searchable by CMake find_package()
MyAPP: a tiny executable depending on MyLIB
The project uses find_package(MyLIB) and creates an executable that uses MyLIB
The problem is that CMake gives me the following error message when configuring the MyAPP project:
CMake Error at CMakeLists.txt:11 (add_executable):
Target "MyAPP" links to target "Qt5::Core" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
The reason for this behaviour is that in the automatically generated MyLIBTargets.cmake file the INTERFACE_LINK_LIBRARIES entry for Qt5 Core is the Qt5::Core symbol. Using Qt4, the absolute path to the Qt core lib was specified here.
Now, I simply can resolve this by using
find_package(Qt5Core 5.X REQUIRED)
in the MyAPP project.
However, I would like to know if this is the intended/generic way to go, i.e. requesting upstream projects of our lib to search for the required transitive Qt5 dependencies themselves, or if I probably misuse CMake here and need to change my configuration procedure?
The CMake docu on package file generation
https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
mentions that macros can be provided by the package configuration files to upstream. Maybe this would be the correct place to search for imported targets like Qt5 and break upstream configuration runs when these dependencies are not found?
Best,
Philipp
[edit of the edit] Full Source Example
You need to deliver a CMake config file for your project, and probably the ConfigFile should be generated via CMake itself (because you cannot know for shure where the user will install your software).
Tip, use the ECM cmake modules to ease the creation of that:
find_package(ECM REQUIRED NO_MODULE)
include(CMakePackageConfigHelpers)
ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX ATCORE
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfigVersion.cmake"
SOVERSION 1
)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5AtCoreConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
and the KF5AtCoreConfig.cmake.in:
#PACKAGE_INIT#
find_dependency(Qt5Widgets "#REQUIRED_QT_VERSION#")
find_dependency(Qt5SerialPort "#REQUIRED_QT_VERSION#")
find_dependency(KF5Solid "#KF5_DEP_VERSION#")
include("${CMAKE_CURRENT_LIST_DIR}/KF5AtCoreTargets.cmake")
This will generate the correct FindYourSortware.cmake with all your dependencies.
[edit] Better explanation on what's going on.
If you are providing a library that will use Qt, and that would also need to find the Qt5 library before compilling the user's source, you need to provide yourself a FindYourLibrary.cmake code, that would call
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Whatever)
Now, if it's your executable that needs to be linked, use the Components instead of the way you are doing it now.
find_package(Qt5 REQUIRED COMPONENTS Core)
then you link your library with
target_link_libraries(YourTarget Qt5::Core)

llvm's cmake integration

I'm currently building a compiler/interpreter in C/C++.
When I noticed LLVM I thought it would fit greatly to what I needed and so I'm trying to integrate LLVM in my existing build system (I use CMake).
I read this bout integration of LLVM in CMake. I copy and pasted the example CMakeLists.txt, changed the LLVM_ROOT to ~/.llvm/ (that's where I downloaded and build LLVM and clang) and it says it isn't a valid LLVM-install. Best result I could achieve was the error message "Can't find LLVMConfig" by changing LLVM_ROOT to ~/.llvm/llvm.
My ~/.llvm/ folder looks like this:
~/.llvm/llvm # this folder contains source files
~/.llvm/build # this folder contains object, executable and library files
I downloaded LLVM and clang via SVN. I did not build it with CMake.
Is it just me or is something wrong with the CMakeLists.txt?
This CMake documentation page got rotted, but setting up CMake for LLVM developing isn't different from any other project. If your headers/libs are installed into non-standard prefix, there is no way for CMake to guess it.
You need to set CMAKE_PREFIX_PATH to the LLVM installation prefix or CMAKE_MODULE_PATH to prefix/share/llvm/cmake to make it work.
And yes, use the second code snippet from documentation (under Alternativaly, you can utilize CMake’s find_package functionality. line).