|
| 1 | +# Self-contained header compilation test |
| 2 | +# |
| 3 | +# Every public header in eckit must compile on its own, without requiring |
| 4 | +# the consumer to include other headers first or in a particular order. |
| 5 | +# This is essential for a library: downstream projects include eckit |
| 6 | +# headers in arbitrary combinations and orders, and a header that silently |
| 7 | +# depends on a transitive include will break when unrelated changes |
| 8 | +# elsewhere shuffle include graphs. Self-contained headers eliminate this |
| 9 | +# class of fragile, hard-to-diagnose build failures for all users. |
| 10 | +# |
| 11 | +# This test generates a .cc file per header (containing only that single |
| 12 | +# #include) and compiles them into one target. A compilation failure |
| 13 | +# immediately identifies the offending header. |
| 14 | +# |
| 15 | +# Gate: -DENABLE_TEST_SELF_CONTAINED_HEADERS=ON (off by default to avoid |
| 16 | +# the extra compile cost on every regular build). |
| 17 | + |
| 18 | +# Glob all public headers under src/eckit/ |
| 19 | +file( GLOB_RECURSE _all_headers |
| 20 | + RELATIVE ${PROJECT_SOURCE_DIR}/src |
| 21 | + ${PROJECT_SOURCE_DIR}/src/eckit/*.h ) |
| 22 | + |
| 23 | +# Exclusions |
| 24 | +list( FILTER _all_headers EXCLUDE REGEX "^eckit/contrib/" ) |
| 25 | + |
| 26 | +set( _skip_headers |
| 27 | + # Must be included via Matrix.h (backend selector guard) |
| 28 | + eckit/maths/MatrixEigen.h |
| 29 | + eckit/maths/MatrixLapack.h |
| 30 | + # Require optional external libraries not always available |
| 31 | + eckit/linalg/detail/CUDA.h # CUDA runtime |
| 32 | + eckit/linalg/detail/HIP.h # HIP runtime |
| 33 | + eckit/io/rados/RadosCluster.h # librados (Ceph) |
| 34 | + eckit/io/rados/RadosHandle.h # librados (Ceph) |
| 35 | + eckit/utils/MD4.h # OpenSSL |
| 36 | + eckit/utils/SHA1.h # OpenSSL |
| 37 | + eckit/geo/area/library/Shapefile.h # shapelib |
| 38 | + # Require MPI headers (only available when ENABLE_MPI=ON) |
| 39 | + eckit/mpi/Parallel.h |
| 40 | + eckit/mpi/ParallelGroup.h |
| 41 | + eckit/mpi/ParallelRequest.h |
| 42 | + eckit/mpi/ParallelStatus.h |
| 43 | + # Coupled to ODB — reference odb:: types from a separate project |
| 44 | + eckit/sql/expression/function/FunctionMATCH.h |
| 45 | + eckit/sql/expression/ShiftedColumnExpression.h |
| 46 | + eckit/sql/SQLIteratorOutput.h |
| 47 | + eckit/sql/SQLMATCHSubquerySession.h |
| 48 | + eckit/sql/SQLMATCHSubquerySessionOutput.h |
| 49 | +) |
| 50 | +list( REMOVE_ITEM _all_headers ${_skip_headers} ) |
| 51 | + |
| 52 | +# Generate one .cc per header |
| 53 | +set( _generated_sources ) |
| 54 | +foreach( _header ${_all_headers} ) |
| 55 | + string( REPLACE "/" "_" _stem ${_header} ) |
| 56 | + string( REPLACE "." "_" _stem ${_stem} ) |
| 57 | + set( _src "${CMAKE_CURRENT_BINARY_DIR}/${_stem}.cc" ) |
| 58 | + file( GENERATE OUTPUT ${_src} |
| 59 | + CONTENT "#include \"${_header}\"\n" ) |
| 60 | + list( APPEND _generated_sources ${_src} ) |
| 61 | +endforeach() |
| 62 | + |
| 63 | +# Compile-only check: an OBJECT library verifies each header compiles |
| 64 | +# standalone without needing a main() or link step. |
| 65 | +if( HAVE_TEST_SELF_CONTAINED_HEADERS ) |
| 66 | + add_library( eckit_test_headers_selfcontained OBJECT ${_generated_sources} ) |
| 67 | + target_link_libraries( eckit_test_headers_selfcontained PUBLIC eckit ) |
| 68 | +endif() |
0 commit comments