CMake can't find IMPORTED library - cmake

In foo/CMakeLists.txt, based on this and this, I have the following
SET (EXTERNAL_LIB_ROOT "../../external_libs/")
ADD_LIBRARY (avcodec-debug STATIC IMPORTED)
SET_PROPERTY (
TARGET avcodec-debug PROPERTY IMPORTED_LOCATION
${EXTERNAL_LIB_ROOT}/libavcodec-0.8.10.a)
In bar/CMakeLists.txt I have this:
# old way uses system libraries
#TARGET_LINK_LIBRARIES (bar avformat avcodec avutil)
# new way uses local debug builds
TARGET_LINK_LIBRARIES (bar avformat avcodec-debug avutil)
When I run make I get
/usr/bin/ld: cannot find -lavcodec-debug
If I revert to the old way, build, touch foo/CMakeLists.txt and rebuild, CMake's configuration output indicates that avcodec-debug is being found by the build system.
So why can't I add it as a dependency?

As it mentioned above by Angew the visibility for imported library differs, though you can extend it using GLOBAL modifier. It might be enough for you to modify add_library call next way:
ADD_LIBRARY(avcodec-debug STATIC IMPORTED GLOBAL)

Imported targets do not follow the same visibility rules as non-imported targets. While non-imported targets are global (visible and accessible from anywhere after they're defined), imported targets are only visible in the CMakeLists.txt where they are defined and below (in directories added by add_subdirectory() in this defining CMakeList).
Since foo is a sibling of bar in your case, the target name avcodec-debug is not visible inside bar/CMakeLists.txt, so it's treated as a normal library name.
It's generally preferred to define imported targets in files you include rather than in their own projects. So change (or extract the relevant parts of) foo/CMakeLists.txt into foo/avcodec.cmake and then in the top-level CMakeList, replace
add_subdirectory(foo)
with
include(foo/avcodec.cmake)

Related

How do I include MTL_HEADER_SEARCH_PATHS in Swift Package Manager Package.swift?

In a internal .metal file in the ShaderPackage defined in Package.swift, I want to include an internal header. That header is nested deeply inside the include folder and I don't want to have to use the relative path. In a non Swift Package Manager (SPM) project, I can just set MTL_HEADER_SEARCH_PATHS to recursively include all subfolders, then include Header.h anywhere in the project without needing to know exactly where it is. (This isn't about exposing either file beyond the package bounds - just an internal-to-package question).
First question: Is there a way to set MTL_HEADER_SEARCH_PATHS from a Package.swift (manifest file for SPM)? Doesn't look like there's any build settings for Metal, only C, CXX, and Swift. Whatever settings I add to cSettings in the form of .headerSearchPath("include/subfolder") doesn't get picked up by Metal, nor .cXXSettings or .swiftSettings. Can I define a custom setting somehow?
Second: If there's a way to set MTL_HEADER_SEARCH_PATHS, can I do it recursively? Or do I have to add each subfolder within include? Thanks!

Get source files from an interface library

I have a header only library I want to write a CMake file for, to be used in other projects. To do this I need to declare the library an interface target. The header files are then added by CMakeList.txt files in subfolders.
Now I want to get the list of source files to run clang-format on them. But get_target_property does not work on interface targets. Is there any way to extract the sources (or headers) from an interface target?
This is the code I have at the moment (not working)
make_minimum_required(VERSION 3.12)
project(foo
LANGUAGES CXX
VERSION 1.0.0)
add_library(bar INTERFACE)
# add header files in sub folders with
target_sources(bar INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/header.h"
)
# this gives the error
get_target_property(MY_SOURCES bar SOURCES)
The error message
INTERFACE_LIBRARY targets may only have whitelisted properties. The
property "SOURCES" is not allowed.
I tried to link the interface target into a real target and get the sources that way, but I only got the sources added directly to the second target, not the sources from the interface target
Because your target is declared as INTERFACE, the target_sources() command populates the INTERFACE_SOURCES property of the target, not SOURCES. From the docs:
The INTERFACE, PUBLIC and PRIVATE keywords are required to specify the scope of the following arguments. PRIVATE and PUBLIC items will populate the SOURCES property of <target>. PUBLIC and INTERFACE items will populate the INTERFACE_SOURCES property of <target>.
Try grabbing the INTERFACE_SOURCES property instead:
add_library(bar INTERFACE)
# add header files in sub folders with
target_sources(bar INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/header.h"
)
# this gives the error
get_target_property(MY_SOURCES bar INTERFACE_SOURCES)

What is the default privacy/scope setting for include_directories?

I understand that target_include_directories() can be used in conjunction with PUBLIC, INTERFACE, or PRIVATE to specify the scope or privacy of the directories. But a lot of antiquated code still uses include_directories(), and I'm not sure how these directories are treated by the targets that use them.
Is using include_directories() essentially the same as using target_include_directories(MyTarget PRIVATE ...)? I have seen this similar question, but is there no default scoping behavior with include_directories() either?
Is using include_directories() essentially the same as using target_include_directories(MyTarget PRIVATE ...)?
Yes, for every target, affected by include_directories (that is, in the current CMakeLists.txt and below), it has the same effect as PRIVATE keyword in target-specific version of the command.
Documentation for include_directories says, that the command assigns INCLUDE_DIRECTORIES property of the targets and directories:
The include directories are added to the INCLUDE_DIRECTORIES directory property for the current CMakeLists file. They are also added to the INCLUDE_DIRECTORIES target property for each target in the current CMakeLists file.
and the directory property affects on further target's ones:
This property is used to populate the INCLUDE_DIRECTORIES target property.
Exactly INCLUDE_DIRECTORIES target property is affected by the PRIVATE keyword of target_include_directories command:
PRIVATE and PUBLIC items will populate the INCLUDE_DIRECTORIES property of <target>. PUBLIC and INTERFACE items will populate the INTERFACE_INCLUDE_DIRECTORIES property of <target>.

Objective C - Unit testing target doesn't recognize classes?

I created a unit test target, that has a dependency on my main target.
Correct me if I'm wrong but adding a dependency should add all the classes from my main target to the unit test target.
Importing classes in unit test target works, but as soon as I try to use these classes in my test target I get the following compile error:
Apple Match-O Linker (ID) Error - _OBJC_CLASS_$_LoginViewcontroller", referenced from:
I know that I could manually add each file to my unit test target but that doesn't seem to be the proper way. Anyone know why adding the dependency doesn't work as expected? Or any way to get around this issue?
I do NOT want to set a "Test Host".
I have to correct you there: Adding a dependency should not add all the classes from yoru main target to the unit test target. It just causes your main target to be built. You additionally have to actually link to your main target.
Update: you can link to your target in the "Link Binary With Libraries" build phase in the "Build Phases" tab.

How do I define a variable when I call CMake, so that qtcreator knows it is defined?

I have a section of code that is conditionally activated depending on a #define, like this:
#ifdef VARIABLE
code.function();
#endif
The cmake script has an 'options' command that sets the VARIABLE like this:
option(VARIABLE "Want to use VARIABLE?" ON)
if(VARIABLE)
message(STATUS "VARIABLE")
set(VARIABLE_FLAG "-DVARIABLE")
endif()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VARIABLE_FLAG} -Wall")
I'm using cmake to build the project and qtcreator as IDE. My problem is that qtcreator thinks that VARIABLE is not defined so my code has is not highlighted, but when I build it on a console, VARIABLE is defined. So, what parameters should I pass to qtcreator to run cmake, so that it knows VARIABLE is defined and highlights my code? Is there a way to do this?
Ps: I just use qtcreator to edit files, the build part is done via console commands.
Another alternative would be to use a configured header file, and include it only where you need the definition:
# in CMakeLists.txt
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/my_defs.h.in
${CMAKE_CURRENT_BINARY_DIR}/my_defs.h
)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
and
// in my_defs.h.in
#cmakedefine VARIABLE
// configure_file converts #cmakedefine of a named CMake variable
// into a C++ #define of a C++ pre-processor symbol
and finally
// in various C++ source or header files, but only as needed:
#include "my_defs.h"
#ifdef VARIABLE
doSome_VARIABLE_SpecificStuff();
#endif
I do not use QtCreator regularly, so I don't know if this technique works in terms of their syntax highlighting, but I'd assume it would, since they must read header files in order to do a proper job of it...
Take a look at add_definitions(). It adds a preprocessor-define to the compiler and can be used like any ordinary #define:
add_definitions( -DVARIABLE )
However... I am not sure if this will make qtcreator pick it up as a 'known variable'.
You can also use the project_name.config file. It is specifically used for your need. You can add defines which are only interpreted by QtCreator for highlighting and auto-completion.
This file is normally in the root folder of your project.