|
25 | 25 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26 | 26 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27 | 27 |
|
28 |
| -function(bundle_libraries output_target) |
| 28 | +function(bundle_libraries output_target library_type) |
| 29 | + |
| 30 | + # 1. Validate the library_type argument |
| 31 | + string(TOUPPER ${library_type} upper_library_type) |
| 32 | + if(NOT (upper_library_type STREQUAL "STATIC" OR upper_library_type STREQUAL "SHARED")) |
| 33 | + message(FATAL_ERROR "bundle_libraries: Invalid library type specified '${library_type}'. Must be STATIC or SHARED for target '${output_target}'.") |
| 34 | + return() # Fatal error stops execution, but return is good practice |
| 35 | + endif() |
| 36 | + |
| 37 | + # Use the validated type in upper case |
| 38 | + set(_target_type ${upper_library_type}) |
| 39 | + |
| 40 | + # --- Inner helper function to get dependencies --- |
| 41 | + # This function recursively finds all dependencies of a given target. |
| 42 | + # It populates a list variable named 'all_dependencies' in the parent scope. |
| 43 | + # Note: This recursive approach with PARENT_SCOPE works but can be a bit |
| 44 | + # tricky with variable lifetimes. It assumes 'all_dependencies' is |
| 45 | + # initialized in the calling scope. |
29 | 46 | function(get_dependencies input_target)
|
| 47 | + # Resolve aliases first |
30 | 48 | get_target_property(alias ${input_target} ALIASED_TARGET)
|
31 | 49 | if(TARGET ${alias})
|
32 | 50 | set(input_target ${alias})
|
33 | 51 | endif()
|
| 52 | + |
| 53 | + # Avoid processing the same target multiple times (circular dependency check) |
| 54 | + # Checks if the current target is already in the list being built in the parent scope. |
| 55 | + # Note: all_dependencies is modified in parent scope below, so check works. |
34 | 56 | if(${input_target} IN_LIST all_dependencies)
|
| 57 | + #message("DEBUG: Already processed ${input_target}") |
35 | 58 | return()
|
36 | 59 | endif()
|
| 60 | + |
| 61 | + # Add the current target to the list in the parent scope |
| 62 | + # list(APPEND) modifies the variable in the current scope. |
| 63 | + # set(... PARENT_SCOPE) copies the current scope's variable to the parent scope. |
| 64 | + # This pattern, while slightly verbose, works for recursive list building across scopes. |
37 | 65 | list(APPEND all_dependencies ${input_target})
|
| 66 | + set(all_dependencies ${all_dependencies} PARENT_SCOPE) # Propagate change up |
38 | 67 |
|
| 68 | + # Get dependencies from LINK_LIBRARIES (Private and Public linkage) |
39 | 69 | get_target_property(link_libraries ${input_target} LINK_LIBRARIES)
|
40 | 70 | foreach(dependency IN LISTS link_libraries)
|
| 71 | + # Only recurse on actual targets |
41 | 72 | if(TARGET ${dependency})
|
42 |
| - get_dependencies(${dependency}) |
| 73 | + #message("DEBUG: Recursing into LINK_LIBRARIES dependency: ${dependency}") |
| 74 | + get_dependencies(${dependency}) # Recursive call |
43 | 75 | endif()
|
44 | 76 | endforeach()
|
45 | 77 |
|
46 |
| - get_target_property(link_libraries ${input_target} INTERFACE_LINK_LIBRARIES) |
47 |
| - foreach(dependency IN LISTS link_libraries) |
| 78 | + # Get dependencies from INTERFACE_LINK_LIBRARIES (Interface and Public linkage) |
| 79 | + get_target_property(interface_link_libraries ${input_target} INTERFACE_LINK_LIBRARIES) |
| 80 | + foreach(dependency IN LISTS interface_link_libraries) |
| 81 | + # Only recurse on actual targets |
48 | 82 | if(TARGET ${dependency})
|
49 |
| - get_dependencies(${dependency}) |
| 83 | + get_dependencies(${dependency}) # Recursive call |
50 | 84 | endif()
|
51 | 85 | endforeach()
|
52 | 86 |
|
53 |
| - set(all_dependencies ${all_dependencies} PARENT_SCOPE) |
54 |
| - endfunction() |
| 87 | + # The final 'all_dependencies' list is available in the parent scope |
| 88 | + # after the initial call to get_dependencies completes. |
| 89 | + |
| 90 | + endfunction() # End of get_dependencies helper function |
| 91 | + # --- End of inner helper function --- |
| 92 | + |
| 93 | + # Initialize the list that the recursive function will populate. |
| 94 | + # This list will exist in the scope of the bundle_libraries function. |
| 95 | + set(all_dependencies "") |
| 96 | + |
| 97 | + # 2. Get dependencies for all input targets provided in ARGN |
| 98 | + # ARGN contains all arguments *after* the named parameters (output_target, library_type) |
| 99 | + if(NOT ARGN) |
| 100 | + message(FATAL_ERROR "bundle_libraries: No input targets specified for '${output_target}'.") |
| 101 | + return() |
| 102 | + endif() |
55 | 103 |
|
56 | 104 | foreach(input_target IN LISTS ARGN)
|
57 |
| - get_dependencies(${input_target}) |
| 105 | + if(TARGET ${input_target}) |
| 106 | + #message("DEBUG: Starting dependency analysis for input target: ${input_target}") |
| 107 | + get_dependencies(${input_target}) |
| 108 | + else() |
| 109 | + message(WARNING "bundle_libraries: Input target '${input_target}' is not a valid target. Skipping.") |
| 110 | + endif() |
58 | 111 | endforeach()
|
59 | 112 |
|
| 113 | + #message("DEBUG: Collected dependencies: ${all_dependencies}") |
| 114 | + |
| 115 | + # 3. Collect $<TARGET_OBJECTS:...> from STATIC and OBJECT library dependencies |
| 116 | + set(all_objects "") |
60 | 117 | foreach(dependency IN LISTS all_dependencies)
|
61 | 118 | get_target_property(type ${dependency} TYPE)
|
| 119 | + # message("DEBUG: Checking dependency ${dependency} with type ${type}") |
| 120 | + |
| 121 | + # We only want object files from static or object libraries. |
| 122 | + # This correctly excludes shared libraries, modules, executables, interfaces, etc. |
62 | 123 | if(${type} STREQUAL "STATIC_LIBRARY")
|
63 | 124 | list(APPEND all_objects $<TARGET_OBJECTS:${dependency}>)
|
64 | 125 | elseif(${type} STREQUAL "OBJECT_LIBRARY")
|
65 | 126 | list(APPEND all_objects $<TARGET_OBJECTS:${dependency}>)
|
66 | 127 | endif()
|
67 | 128 | endforeach()
|
68 | 129 |
|
69 |
| - add_library(${output_target} SHARED ${all_objects}) |
| 130 | + # message("DEBUG: Collected objects: ${all_objects}") |
| 131 | + |
| 132 | + # Check if any object files were found |
| 133 | + if(NOT all_objects) |
| 134 | + message(WARNING "bundle_libraries: No object files found from the dependencies of ${ARGN}. Creating empty library '${output_target}' as ${_target_type}.") |
| 135 | + endif() |
| 136 | + |
| 137 | + # 4. Create the output library using the validated type and collected objects |
| 138 | + # If all_objects is empty, add_library will still create an empty library of the specified type. |
| 139 | + add_library(${output_target} ${_target_type} ${all_objects}) |
70 | 140 |
|
| 141 | + # 5. Add dependencies to ensure input targets are built before the bundled library. |
| 142 | + # This handles the build order correctly. |
71 | 143 | add_dependencies(${output_target} ${ARGN})
|
72 | 144 |
|
73 | 145 | endfunction()
|
0 commit comments