Using exsiting target as base for a new, but related target - cmake

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.

Related

How does Semgrep handle two conflicting Typed Metavariable classes?

Semgrep allows you to specify types in your patterns, but if I happen to have two different classes with the same simple type, but a different fully qualified name, how can I disambiguate between the two when writing a rule where I only want to target one of those types?
I'll explain my question through example. Say you have two different libraries that both have the same class name Foo.
In one file of my own code I import one library, and use the Foo class:
import lib1.* // has Foo class
f = Foo()
f.bar()
In another file of my own code, I import the other library and use it’s Foo class:
import lib2.* // has different Foo class
f2 = Foo()
f2.baz()
In my Semgrep rule, I want to detect things of type Foo from lib1.
pattern: (Foo $F)
Since my pattern doesn’t know anything about imports, does it just return results from both files?
Yes, since your pattern only specifies type Foo, Semgrep will return both f1 and f2 as matches. If you want to match only one of those, you can specify the fully qualified name of the type you want to match:
pattern: (lib1.Foo $F)

Transitive target_include_directories on OBJECT libraries

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)

Is there a way to have a private file constant in Kotlin

Suppose I have some Utils.kt file which will contain only some utility functions, no classes, no objects. And suppose that those functions use some common set of constant values.
So I do something like this:
package myapp
private val CONST1 = 1
private val CONST2 = 2
public fun function1() {}
public fun function2() {}
Unfortunately Kotlin treats private as "available to the whole package".
So CONST1 and CONST2 are available to all files which are in the same package.
The only way to isolate them is to move this file to a separate package.
But what if I have several utility files like this, each with its own set of private constants. Then i have only two options: move each of them to a unique package or give up and have consts from all of them accessible everywhere.
Either way seems to create clutter.
Any options or advice?
(upd: actually, I must say this is one of those rare things that bother me in Kotlin - no way to make some entity be file-local (without using some syntax hacks): it's either available to whole package or to everyone at all)
UPD: This question is now obsolete (see the accepted answer)
Top-level declarations with private visibility are visible only in the file where they are declared.
(original answer, valid when the question was asked: Kotlin does not have any concept of file-local scope, and to the best of my knowledge there are no plans to introduce it. If you don't like package scope (why?), you can create an object encapsulating the functions and the private constants that they use.

Clarification of the term "Namespace"

My understanding of the term "namespace" is essentially that of a class; a container of methods and variables. Although that seems to be doubling up on what I consider to be the definition of a class.
Can someone confirm or clarify that belief?
I would say a namespace is a way of logically grouping symbols (classes, functions, ... depending on the exact language you're working with) in a container that ensures that those symbols don't collide with other symbols (which could have the same name) in other namespaces.
Namespace is mainly used for avoiding name conflicts. Suppose if you a class named A but this class may be defined by others . so in this cases you need to separate your class from others. In that instance Namespace is come to act. For eg: you given namespace 'using yourname ' in this name space you defined a class A. so that this class can be distinguished by yourname.A. similary for methods ,variables all thing you can defined in your own namespace.
A namespace is used to have different programming rules in the same program module. Let's say you want to define the function 'string_addition' to mean 'string1' + 'string2' = 'string1string2', but later in the same program you want to define 'string_addition' to mean 'string1' + 'string2' = 'string3'. You can use namespaces, so that in the same file you can call on the different namespaces and get both kinds of rules.
namespace h:stringadd(string1, string2) = string1string2
namespace f:stringadd(string1, string2) = string3
a namespace provides a context for an identifier you are referring to. So in that sense, a class is also a namespace.
In the general sense, a namespace defines a set of names which are unique. In other words, a name is only unique within a namespace.
As this concept applies to different languages, there are many variants that include issues like encapsulation, namepsacing, scope and so on.
A namespace is the domain in which a given name remains unique. For example you may define many classes named Widget but they must all appear within seperate domains to be uniquely identifiable from one another.
The domain in which a name appears depends upon the context in which it is defined. For example in the .NET world, a class name must be unique within a namespace, which itself must be unique within an assembly, so one could say that the domain in which a class name is unique is a namespace and the domain of a namespace is an assembly
Namespace is a group of classes. It becomes a .dll after compilation. So we can add that .dll file to our project and can easily use those classes.
Namespaces aren't a feature of OOP. Specify a programming language.
And, yes, in general they are similar to classes, but only those classes which contain no non-static members (since a namespace couldn't be instantiated to form an object).

How to get MATLAB to recognise newly added static methods?

I am using classes and static methods to 'scope' functions in a namespace, similar to C#. However, every time I add a new method to a class, at first it is not found. I have to restart the MATLAB environment (2007a) for the new methods to be recognised.
Surely there is an 'update' or 'refresh' type command that I can use so that I do not have to restart the MATLAB environment each time I add a function?
Issuing this call to CLEAR should do it:
clear classes
One unfortunate side effect of this is that it also effectively issues a clear all, which clears all of the variables in the workspace as well (however, this would happen anyway when you close and restart MATLAB). This clearing of the workspace actually serves a purpose, since it will remove any variables of the same type as the old version of your class, which potentially wouldn't work correctly with the new version of your class.
The function REHASH may work, but I doubt it (I think it deals more with file paths than class definitions).
Clearing instances of your class should work.
Suppose that you have an instance of "MyClass" in your base workspace:
foo = MyClass;
Now, suppose you edit MyClass and add new static method "bar":
foo.bar(); % Will cause error, as foo is instance of previous "MyClass"
However, "clear"-ing foo will remove the reference to the previous class:
clear('foo');
foo = MyClass;
foo.bar(); % this should now work.
This should be fine if you only have one or two instances of the class in your base workspace. If you have many instances of the class in your base workspace, then you may want to write a script to clear them:
varList = whos;
for iVar = 1:numel(varList)
if isequal( 'MyClass', varList(iVar).class )
clear( varlist(iVar).name );
end
end
clear('varList');
clear('MyClass');
If you have instances of the class in more locations, you may wish to extend the script as appropriate.
The last call to clear the class name might only be necessary if you are making modifications to classes in an inheritance hierarchy.
try "clear classname"