Proposal: Header file for compile‐time configuration
For the sake of this discussion, a "configured" OpenDDS is ready to be built by some build system. User options such as those listed on https://opendds.readthedocs.io/en/latest-release/devguide/building/index.html impact compile-time configuration.
Runtime configuration options (ini file, argv options, environment) are out of scope for this discussion.
Users can configure OpenDDS using any of:
- Manual configuration + mwc.pl
- configure script
- CMake
The results of configuration decisions made by the user are currently encoded in a number of files in different locations:
- MPC's
default.features
- OpenDDS
user_macros.GNU
(if using gnuace) - Generated makefiles/project files
- Options that impact ACE need to be in ACE's configuration files, or in MPC features which are common to ACE and OpenDDS
- Some options that don't impact ACE are put in ACE's configuration files anyway (not sure if that's still true)
- Wherever possible, centralize configuration options in a single file
- The same file should be used for all configuration methods, platforms, build systems
- Options that impact the ACE build (xerces3) will need to also appear in ACE
- Options that determine which targets should be built need to be known to the build system
- The file should be a preprocessor header since that format is common and easily understood
- This header should only have preprocessor directives (and comments)
- A preprocessor header that doesn't
#include
other headers that have C/C++ declarations can be#include
d from IDL
The initial "build OpenDDS with CMake" effort resulted in a .h.in
file committed to git which CMake transforms to a .h
file. This file currently doesn't contain any configuration options. It defines a preprocessor macro which selectively enables the OPENDDS_USES_AUTO_STATIC_INCLUDES
feature only when CMake is used as the build system.
In https://github.com/OpenDDS/OpenDDS/pull/4482, this .h.in
mechanism was generalized to work outside of CMake. The same .h.in
file is now read and processed by configure and CMake. Assuming 4482 gets merged, the output file is /dds/OpenDDSConfig.h
Currently OpenDDSConfig.h is optionally #include
d from Definitions.h using __has_include
(C++17) if the compiler supports it.
With expanded use of OpenDDSConfig.h, it needs to work on all supported compilers.
Option A: make it required
Downside is that users doing manual configuration (includes some uses of autobuild) need to change their build scripts to (at least) write an empty file.
Option B: keep it optional
Without depending on __has_include
, the following scheme can allow it to be optional:
- Put an empty
OpenDDSConfig.h
in the root of the repository - Add
$(DDS_ROOT)/dds/config
as an-I
include path that appears before$(DDS_ROOT)
- If the user doesn't have their own
OpenDDSConfig.h
on the include path, the one from$(DDS_ROOT)
will be used
The config file will be required to make maintainability easier.
OPENDDS_CONFIG_*
or OPENDDS_USES_*
or OPENDDS_HAS_*
Macros will be named OPENDDS_CONFIG_
to differentiate them from existing macros.
After the config header is included, code can assume that each macro has the value 0 or 1.
This is opposed to previous way macros where used, where macros are either defined or not defined to represent their value, then it's checked using some form of defined
.
This has many advantages:
- Using always defined values of 0 or 1 means checking can directly use the preprocessor logic.
- It results in downstream code that can check for existence to determine if OpenDDS knows about the value in the first place. This will make writing backwards compatible code easier.
- It will allow us to check for misspelled or removed macro names if we can use
-Wundef
at some point.
There may be some cases where more info than a bool is needed (for example, a version number).
Changing existing macros to meet the naming convention needs to be done carefully to preserve compatibility with downstream code (applications or code in other repos).
Existing | Proposed | Notes |
---|---|---|
DDS_HAS_MINIMUM_BIT |
OPENDDS_CONFIG_BUILT_IN_TOPICS |
inverted logic |
OPENDDS_NO_CONTENT_SUBSCRIPTION_PROFILE |
OPENDDS_CONFIG_CONTENT_SUBSCRIPTION_PROFILE |
see below |
OPENDDS_NO_QUERY_CONDITION |
OPENDDS_CONFIG_QUERY_CONDITION |
|
OPENDDS_NO_CONTENT_FILTERED_TOPIC |
OPENDDS_CONFIG_CONTENT_FILTERED_TOPIC |
|
OPENDDS_NO_MULTI_TOPIC |
OPENDDS_CONFIG_MULTI_TOPIC |
|
OPENDDS_NO_OWNERSHIP_PROFILE |
OPENDDS_CONFIG_OWNERSHIP_PROFILE |
|
OPENDDS_NO_OWNERSHIP_KIND_EXCLUSIVE |
OPENDDS_CONFIG_OWNERSHIP_KIND_EXCLUSIVE |
|
OPENDDS_NO_OBJECT_MODEL_PROFILE |
OPENDDS_CONFIG_OBJECT_MODEL_PROFILE |
|
OPENDDS_NO_PERSISTENCE_PROFILE |
OPENDDS_CONFIG_PERSISTENCE_PROFILE |
|
OPENDDS_SAFETY_PROFILE |
OPENDDS_CONFIG_SAFETY_PROFILE |
|
OPENDDS_SECURITY |
OPENDDS_CONFIG_SECURITY |
|
OPENDDS_HAS_CXX11 |
OPENDDS_CONFIG_CXX11 |
|
OPENDDS_RAPIDJSON |
OPENDDS_CONFIG_RAPIDJSON |
|
OPENDDS_USES_AUTO_STATIC_INCLUDES |
OPENDDS_CONFIG_AUTO_STATIC_INCLUDES |
not user-configurable |
These all match CMake feature names except for CONTENT_SUBSCRIPTION_PROFILE
. It's CONTENT_SUBSCRIPTION
ultimately because that's what the configure script option name is.
A pattern used by ACE is to have a wrapper file that sets defaults. This can help with backwards-compatibility for existing macros.
OpenDDS will use a wrapper to provide default values if the user does not configure an option.
In addition to including the config header and defaulting the OPENDDS_CONFIG_*
values, the wrapper file could do some addition things:
-
Basic consistency checks on the
OPENDDS_CONFIG_*
values. -
From
Defintions.h
:- As part of the
OPENDDS_CONFIG_*
values defaulting code:OPENDDS_NO_CONTENT_SUBSCRIPTION_PROFILE
OPENDDS_USES_AUTO_STATIC_INCLUDES
- The
#include <tao/idl_features.h>
block, but it would need some tweaks to work properly in both C++ and IDL. See here for details.
- As part of the
-
Define the old forms of the
OPENDDS_CONFIG_*
values for user compatibility. Maybe to be dropped in OpenDDS 4? For example:#if !OPENDDS_CONFIG_QUERY_CONDITION # define OPENDDS_NO_QUERY_CONDITION #elif defined OPENDDS_NO_QUERY_CONDITION # undef OPENDDS_NO_QUERY_CONDITION #endif
An alternative would be to keep these definitions defined using
-D
.