Feature Request: Support for DIRECTORY scoped non-IMPORTED library/executable targets
Problem
Currently CMake(3.23.0) targets that are declared as an IMPORTED library/executable target are by default scoped to the DIRECTORY, with the option to promote the IMPORT library target scope to GLOBAL.
Libraries and executable target that are not marked IMPORTED have a GLOBAL scope by default. There is no way to restrict a non-IMPORTED target to have DIRECTORY scope.
Pretty much I am looking for the reverse functionality of an IMPORTED target, that would allow a non-IMPORTED target to be marked as scoped to a Directory.
Why is this feature needed?
I work on the O3DE(Open 3D Engine) codebase where we use CMake as our build generator.
The O3DE project supports a plugin system(called a Gem), which uses CMake add_subdirectory command to allow for libraries to hook into the O3DE build system.
For users that wish to make a new plugin it is desired expose a CMakeLists.txt template that allow the plugin author to expose a public API INTERFACE target and several runtime MODULE targets.
Other plugins are allowed to depend on the INTERFACE target to access the public API, while the MODULES targets are loaded by either the O3DE Editor application or runtime launcher application.
Now MODULE targets have shared code between them that we encapsulate via using a OBJECT/STATIC library that we wish to keep private to the plugin's CMakeLists.txt and any subdirectories.
The layout structure for a plugin in simple terms would look like the following(The actual layout can be seen here
GemPlugin1/
CMakeLists.txt
Include/
Editor/
editor_public1.h
Runtime/
public1.h
public2.h
Source/
Editor/
editor_private1.cpp
private1.h
private1.cpp
private2.cpp
plugin_hook.cpp
editor_plugin_hook.cpp
With that kind of layout:
- We expose a public "GemPlugin1.API" INTERFACE target that other users can depend on to access to the public Includes
- Have two MODULE target, one for the "editor" and one for the "runtime"
- Have a private OBJECT target that can only be used by the MODULE targets within the CMakeLists.txt(or any descendant CMakeLists.txt) to specify shared build setup(private source files, compile options, include directories, etc.
# This is the public target, that other libraries can use
add_library(GemPlugin1.API INTERFACE)
target_include_directories(GemPlugin1.API INTERFACE "Include")
target_sources(GemPlugin1.API INTERFACE Editor/editor_public1.h public1.h public2.h)
# This is the private target, that only the MODULE targets within this CMakeLists.txt can use to reduce multiple compilations of source artifacts
add_library(GemPlugin1.Private.Object OBJECT)
target_include_directories(GemPlugin1.Private.Object PRIVATE "Source")
target_sources(GemPlugin1.Private.Object PRIVATE Editor/editor_private1.cpp private1.h private2.cpp private2.cpp)
# This is the runtime MODULE target, that uses the private target to ingest shared build properties
add_library(GemPlugin1 MODULE)
target_include_directories(GemPlugin1 PRIVATE "Source)
target_sources(GemPlugin1 plugin_hook.cpp)
target_link_libraries(GemPlugin1 PRIVATE GemPlugin1.Private.Object)
# This is the editor MODULE target, that uses the private target to ingest shared build properties
add_library(GemPlugin1.Editor MODULE)
target_include_directories(GemPlugin1.Editor PRIVATE "Source)
target_sources(GemPlugin1.Editor plugin_hook.cpp)
target_link_libraries(GemPlugin1.Editor PRIVATE GemPlugin1.Private.Object)
With that kind of layout we want to prevent users that depend on the "GemPlugin1" plugin from attempting to use the private GemPlugin1.Private.Object
library outside of the "GemPlugin1" directory, but because non-IMPORTED libraries/executables have GLOBAL scope by default, nothing prevents user from actually accessing the private OBJECT library
Request
The ask here is for an way to mark a normal library/executable target as having DIRECTORY scope instead of GLOBAL scope.
Perhaps there could be an option such as DIRECTORY that can be supplied to add_library/add_executable
For example to mark a library as private for that CMakeLists.txt scope, one could do the following
add_library(GemPlugin1.Private.Object OBJECT DIRECTORY) # "GemPlugin1.Private.Object" target is only visible within this directory