Skip to content

Proposal: Header file for compile‐time configuration

Fred Hornsey edited this page Feb 29, 2024 · 13 revisions

Background

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:

  1. Manual configuration + mwc.pl
  2. configure script
  3. CMake

The results of configuration decisions made by the user are currently encoded in a number of files in different locations:

  1. MPC's default.features
  2. OpenDDS user_macros.GNU (if using gnuace)
  3. Generated makefiles/project files
  4. Options that impact ACE need to be in ACE's configuration files, or in MPC features which are common to ACE and OpenDDS
  5. Some options that don't impact ACE are put in ACE's configuration files anyway (not sure if that's still true)

Goals

  • 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 #included from IDL

Progress

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

Next steps and design decisions

Optional or required?

Currently OpenDDSConfig.h is optionally #included 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.

Names and values of preprocessor macros

Names

OPENDDS_CONFIG_* or OPENDDS_USES_* or OPENDDS_HAS_*

Macros will be named OPENDDS_CONFIG_ to differentiate them from existing macros.

Value format

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).

Compatibility

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).

Values to include

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.

Wrapper include file

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.

Contents

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.
  • 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.