I always confused when CMake documents say "populate the property". For example in
target_include_directories( [SYSTEM] [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE>
[items2...] ...])
...
PRIVATE and PUBLIC items will populate the INCLUDE_DIRECTORIES
property of <target>.
I'm not sure to populate the 'INCLUDE_DIRECTORIES' property with what?
For example target_include_directories(A PUBLIC B), does 'populate INCLUDE_DIRECTORIES' here means to copy B's INCLUDE_DIRECTORIES propery into A's INCLUDE_DIRECTORIES property?
PRIVATE and PUBLIC items will populate the INCLUDE_DIRECTORIES property of <target>.
It roughly does:
set(mode "PRIVATE") # or PUBLIC, from target_include_directories arguments
# Get interface include directories
target_get_proprety(incdirs B INTERFACE_INCLUDE_DIRECTORIES)
if(mode STREQUAL "PUBLIC" OR mode STREQUAL "PRIVATE")
set_properties(TARGET A APPEND PROPERTY INCLUDE_DIRECTORIES ${incdirs})
endif()
# when mode is PUBLIC or INTERFACE, they get also added to A's INTERFACE_INCLUDE_DIRECTORIES
I think the word "populate" there could be replaced with "append" without losing meaning.
I'm not sure to populate the 'INCLUDE_DIRECTORIES' property with what?
With the content of INTERFACE_INCLUDE_DIRECTORIES from the other target.
For example target_include_directories(A PUBLIC B), does 'populate INCLUDE_DIRECTORIES' here means to copy B's INCLUDE_DIRECTORIES propery into A's INCLUDE_DIRECTORIES property?
Means to append B's INTERFACE_INCLUDE_DIRECTORIES into A's INCLUDE_DIRECTORIES and into A's INTERFACE_INCLUDE_DIRECTORIES.
Related
Say I have a cmake script with:
...
add_executable(ABC abc.cpp)
...
with some properties set, libraries linked etc.
Now I'd like to define a derived target, say ABC-extended based on ABC in the same CMakeLists.txt file, that would have all the same properties, libraries linked etc, but with a couple of new compiler flags passed say -O3 or whatever, without redefining all that.
I.e., I'd like something like this (fictional functions used):
add_derived_executable(ABC2 FROM ABC)
add_target_compile_options(ABC2 PUBLIC -O3)
You can use an INTERFACE library as base target that holds all your common flags/sources/properties (a.k.a. usage requirements). Those can then be propagated to all your derived libraries via target_link_libraries():
# base library
add_library(ABC-base)
target_compile_options(ABC-base INTERFACE ...)
target_sources(ABC-base INTERFACE ...)
# derived libraries
add_library(ABC)
target_link_libraries(ABC PRIVATE ABC-base)
add_library(ABC-extended)
target_link_libraries(ABC-extended PRIVATE ABC-base)
target_compile_options(ABC-extended PRIVATE -O3)
Note, that the base target should be "linked" PRIVATEly against the derived ones, to prevent the flags/sources/properties of the base target being passed on to other targets that link against e.g. the ABC library.
The MSDN article on #If Then #Else (https://msdn.microsoft.com/en-us/library/tx6yas69.aspx) gives me the basics on conditionally compiling conditional statements.
I happen to have longer lists of declarations that must be initialized differently, based upon multiple platforms. Am I required to use #ElseIf at compile time, or is there a #Select Case option too?
No there are no #Select Case directives in VB .Net (as pointed out by Icepickle)
According to Conditional Compilation, you can define compilation constants #Const and test them to include or exclude blocks of code.
If you have a lot of different architectures/platforms, maybe it is better to write a different file for each platform, and protect the file with the constant check
First you declare an interface so the rest of your code will always be able to find what it needs :
Public Interface IPlatformDependant
Property Test1 As Integer
'Define here all the parameters used by your application
End Interface
File platform1.vb :
#If Platform = 1
'The code for the first platform
Public Class PlatformDependant
Implements IPlatformDependant
Public Property Test1 As Integer Implements IPlatformDependant.Test1
End Class
#End If
File platform2.vb :
#If Platform = 2
'The code for the second platform
Public Class PlatformDependant
Implements IPlatformDependant
Public Property Test1 As Integer Implements IPlatformDependant.Test1
End Class
#End If
In your project designer, you define platform to which you want, and only one class PlatformDependant will be used at a time. The classname can even stay the same...
The Interface here is optional, but it makes you sure that all your classes implements the required method.
Here is snippet from make CMakeLists.txt:
add_library(foo-object OBJECT src/foo.cpp)
target_include_directories(foo-object PUBLIC include)
add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
add_library(foo_static STATIC $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
Now, this all works fine, both libraries are generated. However I have a problem when I try to use it:
add_executable(bar src/main.cpp)
target_link_libraries(bar foo)
Target bar doesn't compile, because include directories from foo-object are not propagated. If I add target_include_directories directly on foo as well, everything will compile fine.
How can I make both foo and foo_static automatically use (and forward to stuff depending on them) include directories from foo-object?
Hm, at the moment I came up with following:
add_library(foo-object OBJECT src/foo.cpp)
target_include_directories(foo-object PUBLIC include)
get_property(object_include_dirs TARGET foo-object PROPERTY INCLUDE_DIRECTORIES)
get_property(object_link_libs TARGET foo-object PROPERTY LINK_LIBRARIES)
add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo PUBLIC ${object_include_dirs})
target_link_libraries(foo PUBLIC ${object_link_libs})
add_library(foo_static STATIC $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo_static PUBLIC ${object_include_dirs})
target_link_libraries(foo_static PUBLIC ${object_link_libs})
but come on, there must be better way :/
It seems that transitive properties only work when targets are linked through a chain of target_link_library calls. In your case, you do not have such a link between foo-object and foo.
If you add a source file to foo, that one should also not be able to see the include directory from foo-object.
This might be an oversight in the design of OBJECT libraries, as it essentially breaks the transitive properties for those.
On CMake <3.12, use the following:
add_library(foo SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
target_include_directories(foo
PRIVATE
$<TARGET_PROPERTY:${PROJECT_NAME}-object,INTERFACE_INCLUDE_DIRECTORIES>)
On CMake >=3.12, take a look at this answer (thanks #ian5v for the suggestion)
How it works:
target_include_directories(...)
...
PUBLIC and INTERFACE items will populate the INTERFACE_INCLUDE_DIRECTORIES property of <target>.
Therefore ${PROJECT_NAME}-object has INTERFACE_INCLUDE_DIRECTORIES set on it. We need to fetch this property and insert it into our own include path.
This looks like a job for "generator expressions"!. In particular, $<TARGET_PROPERTY:tgt,prop> looks like it will come in handy here.
Our tgt will be ${PROJECT_NAME}-object, and we're trying to extract all of the values of INTERFACE_INCLUDE_DIRECTORIES, so INTERFACE_INCLUDE_DIRECTORIES will be prop.
This comes out to $<TARGET_PROPERTY:${PROJECT_NAME}-object,INTERFACE_INCLUDE_DIRECTORIES>, which is exactly what we've used in the code above.
For me something like the following seems to be working:
add_library(foo_objects OBJECT src/foo.cpp src/foo.hpp)
set_property(TARGET foo_objects PROPERTY POSITION_INDEPENDENT_CODE ON)
target_include_directories(foo_objects PUBLIC
"$<BUILD_INTERFACE:src>"
"$<INSTALL_INTERFACE:include>")
add_library(foo_shared SHARED)
add_library(foo_static STATIC)
target_link_libraries(foo_shared PUBLIC foo_objects)
target_link_libraries(foo_static PUBLIC foo_objects)
Does it even exist? I want to have a shared variable across a module and a class that belong to the same project.
Shared variables exist but you probably mean the old fashioned Global variables. For that, just declare a variable in an actual module rather than a Class:
Friend Foo As Integer
Public Bar As String = ""
Static vars are quite different
you can look into static variables. that's probably the closest thing to shared variables.
I'd like to add verbose information about my core classes without embedding it all above those classes in the source file.
For instance, I'd like to create a separate file with voluminous info about class Foo, probably in markdown or html. Then when I view class Foo in the doxygen-created output, I'd like the class page for Foo to contain all my voluminous and beautifully marked up documentation in its details section along with any other comments I did put above class Foo.
Is this possible?
If you currently have a file Foo.h
/**
A short description of class Foo.
*/
class Foo
{
}
You can add additional documentation in a file with a .dox extension (let's call it Foo.dox)
/**
More details about Foo.
Maybe you only want to distribute this to your nicer customers.
#class Foo Foo.h
*/
Don't forget to add the .dox file to the INPUT line of your configuration file
INPUT = \
Foo.h Foo.dox