diff options
author | Tue Ly <lntue.h@gmail.com> | 2022-05-08 20:45:40 +0300 |
---|---|---|
committer | Tue Ly <lntue@google.com> | 2022-06-01 07:54:07 +0300 |
commit | 800051487f13e5506502c0c4021a97a53b89bcde (patch) | |
tree | 575cf333eec3e87f02c877714f43866a0db1432e /libc/cmake/modules/LLVMLibCObjectRules.cmake | |
parent | 17296607a761086b2c0e6518ceaa16415dceb55b (diff) |
[libc] Implement FLAGS option for generating all combinations for targets.
Add FLAGS option for add_header_library, add_object_library,
add_entrypoint_object, and add_libc_unittest.
In general, a flag is a string provided for supported functions under the
multi-valued option `FLAGS`. It should be one of the following forms:
FLAG_NAME
FLAG_NAME__NO
FLAG_NAME__ONLY
A target will inherit all the flags of its upstream dependency.
When we create a target `TARGET_NAME` with a flag using (add_header_library,
add_object_library, ...), its behavior will depend on the flag form as follow:
- FLAG_NAME: The following 2 targets will be generated:
`TARGET_NAME` that has `FLAG_NAME` in its `FLAGS` property.
`TARGET_NAME.__NO_FLAG_NAME` that depends on `DEP.__NO_FLAG_NAME` if
`TARGET_NAME` depends on `DEP` and `DEP` has `FLAG_NAME` in its `FLAGS`
property.
- FLAG_NAME__ONLY: Only generate 1 target `TARGET_NAME` that has `FLAG_NAME`
in its `FLAGS` property.
- FLAG_NAME__NO: Only generate 1 target `TARGET_NAME.__NO_FLAG_NAME` that
depends on `DEP.__NO_FLAG_NAME` if `DEP` is in its DEPENDS list and `DEP`
has `FLAG_NAME` in its `FLAGS` property.
To show all the targets generated, pass SHOW_INTERMEDIATE_OBJECTS=ON to cmake.
To show all the targets' dependency and flags, pass
`SHOW_INTERMEDIATE_OBJECTS=DEPS` to cmake.
To completely disable a flag FLAG_NAME expansion, set the variable
`SKIP_FLAG_EXPANSION_FLAG_NAME=TRUE`.
Reviewed By: michaelrj, sivachandra
Differential Revision: https://reviews.llvm.org/D125174
Diffstat (limited to 'libc/cmake/modules/LLVMLibCObjectRules.cmake')
-rw-r--r-- | libc/cmake/modules/LLVMLibCObjectRules.cmake | 301 |
1 files changed, 258 insertions, 43 deletions
diff --git a/libc/cmake/modules/LLVMLibCObjectRules.cmake b/libc/cmake/modules/LLVMLibCObjectRules.cmake index 8e2f489752a6..ae49e136615e 100644 --- a/libc/cmake/modules/LLVMLibCObjectRules.cmake +++ b/libc/cmake/modules/LLVMLibCObjectRules.cmake @@ -1,7 +1,7 @@ set(OBJECT_LIBRARY_TARGET_TYPE "OBJECT_LIBRARY") function(_get_common_compile_options output_var) - set(compile_options ${LLVM_CXX_STD_default} ${LIBC_COMPILE_OPTIONS_DEFAULT} ${ARGN}) + set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT} ${ARGN}) if(NOT ${LIBC_TARGET_OS} STREQUAL "windows") set(compile_options ${compile_options} -fpie -ffreestanding) endif() @@ -26,12 +26,13 @@ endfunction() # SRCS <list of source files> # DEPENDS <list of dependencies> # COMPILE_OPTIONS <optional list of special compile options for this target> -function(add_object_library target_name) +# FLAGS <optional list of flags> +function(create_object_library fq_target_name) cmake_parse_arguments( "ADD_OBJECT" "" # No optional arguments "CXX_STANDARD" # Single value arguments - "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS" # Multivalue arguments + "SRCS;HDRS;COMPILE_OPTIONS;DEPENDS;FLAGS" # Multivalue arguments ${ARGN} ) @@ -39,7 +40,6 @@ function(add_object_library target_name) message(FATAL_ERROR "'add_object_library' rule requires SRCS to be specified.") endif() - get_fq_target_name(${target_name} fq_target_name) add_library( ${fq_target_name} EXCLUDE_FROM_ALL @@ -58,24 +58,126 @@ function(add_object_library target_name) target_compile_options(${fq_target_name} PRIVATE ${compile_options}) get_fq_deps_list(fq_deps_list ${ADD_OBJECT_DEPENDS}) + + if(SHOW_INTERMEDIATE_OBJECTS) + message(STATUS "Adding object library ${fq_target_name}") + if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS") + foreach(dep IN LISTS ADD_OBJECT_DEPENDS) + message(STATUS " ${fq_target_name} depends on ${dep}") + endforeach() + endif() + endif() + if(fq_deps_list) add_dependencies(${fq_target_name} ${fq_deps_list}) endif() - if(ADD_OBJECT_CXX_STANDARD) - set_target_properties( - ${fq_target_name} - PROPERTIES - CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD} - ) + if(NOT ADD_OBJECT_CXX_STANDARD) + set(ADD_OBJECT_CXX_STANDARD ${CMAKE_CXX_STANDARD}) endif() - + set_target_properties( ${fq_target_name} PROPERTIES - "TARGET_TYPE" ${OBJECT_LIBRARY_TARGET_TYPE} - "OBJECT_FILES" "$<TARGET_OBJECTS:${fq_target_name}>" - "DEPS" "${fq_deps_list}" + TARGET_TYPE ${OBJECT_LIBRARY_TARGET_TYPE} + OBJECT_FILES "$<TARGET_OBJECTS:${fq_target_name}>" + CXX_STANDARD ${ADD_OBJECT_CXX_STANDARD} + DEPS "${fq_deps_list}" + FLAGS "${ADD_OBJECT_FLAGS}" + ) +endfunction(create_object_library) + +# Internal function, used by `add_object_library`. +function(expand_flags_for_object_library target_name flags) + cmake_parse_arguments( + "EXPAND_FLAGS" + "IGNORE_MARKER" # Optional arguments + "" # Single-value arguments + "DEPENDS;FLAGS" # Multi-value arguments + ${ARGN} + ) + + list(LENGTH flags nflags) + if(NOT ${nflags}) + create_object_library( + ${target_name} + DEPENDS ${EXPAND_FLAGS_DEPENDS} + FLAGS ${EXPAND_FLAGS_FLAGS} + ${EXPAND_FLAGS_UNPARSED_ARGUMENTS} + ) + return() + endif() + + list(POP_FRONT flags flag) + extract_flag_modifier(${flag} real_flag modifier) + + if(NOT "${modifier}" STREQUAL "NO") + expand_flags_for_object_library( + ${target_name} + "${flags}" + DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER + FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER + "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}" + ) + endif() + + if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY") + return() + endif() + + set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS}) + list(REMOVE_ITEM NEW_FLAGS ${flag}) + get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS}) + + # Only target with `flag` has `.__NO_flag` target, `flag__NO` and + # `flag__ONLY` do not. + if(NOT "${modifier}") + set(TARGET_NAME "${target_name}.__NO_${flag}") + else() + set(TARGET_NAME "${target_name}") + endif() + + expand_flags_for_object_library( + ${TARGET_NAME} + "${flags}" + DEPENDS "${NEW_DEPS}" IGNORE_MARKER + FLAGS "${NEW_FLAGS}" IGNORE_MARKER + "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}" + ) +endfunction(expand_flags_for_object_library) + +function(add_object_library target_name) + cmake_parse_arguments( + "ADD_TO_EXPAND" + "" # Optional arguments + "" # Single value arguments + "DEPENDS;FLAGS" # Multi-value arguments + ${ARGN} + ) + + get_fq_target_name(${target_name} fq_target_name) + + if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS")) + message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}") + endif() + + get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS}) + get_flags_from_dep_list(deps_flag_list ${fq_deps_list}) + + list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list}) + remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags) + list(SORT flags) + + if(SHOW_INTERMEDIATE_OBJECTS AND flags) + message(STATUS "Object library ${fq_target_name} has FLAGS: ${flags}") + endif() + + expand_flags_for_object_library( + ${fq_target_name} + "${flags}" + DEPENDS "${fq_deps_list}" IGNORE_MARKER + FLAGS "${flags}" IGNORE_MARKER + ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS} ) endfunction(add_object_library) @@ -92,29 +194,24 @@ set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ") # DEPENDS <list of dependencies> # COMPILE_OPTIONS <optional list of special compile options for this target> # SPECIAL_OBJECTS <optional list of special object targets added by the rule `add_object`> +# FLAGS <optional list of flags> # ) -function(add_entrypoint_object target_name) +function(create_entrypoint_object fq_target_name) cmake_parse_arguments( "ADD_ENTRYPOINT_OBJ" "ALIAS;REDIRECTED" # Optional argument "NAME;CXX_STANDARD" # Single value arguments - "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi value arguments + "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;FLAGS" # Multi value arguments ${ARGN} ) - get_fq_target_name(${target_name} fq_target_name) - set(entrypoint_name ${target_name}) - if(ADD_ENTRYPOINT_OBJ_NAME) - set(entrypoint_name ${ADD_ENTRYPOINT_OBJ_NAME}) - endif() - - list(FIND TARGET_ENTRYPOINT_NAME_LIST ${entrypoint_name} entrypoint_name_index) + list(FIND TARGET_ENTRYPOINT_NAME_LIST ${ADD_ENTRYPOINT_OBJ_NAME} entrypoint_name_index) if(${entrypoint_name_index} EQUAL -1) add_custom_target(${fq_target_name}) set_target_properties( ${fq_target_name} PROPERTIES - "ENTRYPOINT_NAME" ${entrypoint_name} + "ENTRYPOINT_NAME" ${ADD_ENTRYPOINT_OBJ_NAME} "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} "OBJECT_FILE" "" "OBJECT_FILE_RAW" "" @@ -134,6 +231,12 @@ function(add_entrypoint_object target_name) endif() list(GET ADD_ENTRYPOINT_OBJ_DEPENDS 0 dep_target) get_fq_dep_name(fq_dep_name ${dep_target}) + + if(SHOW_INTERMEDIATE_OBJECTS) + message(STATUS "Adding entrypoint object ${fq_target_name} as an alias of" + " ${fq_dep_name}") + endif() + if(NOT TARGET ${fq_dep_name}) message(WARNING "Aliasee ${fq_dep_name} for entrypoint alias ${target_name} missing; " "Target ${target_name} will be ignored.") @@ -152,12 +255,13 @@ function(add_entrypoint_object target_name) set_target_properties( ${fq_target_name} PROPERTIES - "ENTRYPOINT_NAME" ${entrypoint_name} - "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} - "IS_ALIAS" "YES" - "OBJECT_FILE" "" - "OBJECT_FILE_RAW" "" - "DEPS" "${fq_dep_name}" + ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME} + TARGET_TYPE ${ENTRYPOINT_OBJ_TARGET_TYPE} + IS_ALIAS "YES" + OBJECT_FILE "" + OBJECT_FILE_RAW "" + DEPS "${fq_dep_name}" + FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}" ) return() endif() @@ -168,6 +272,9 @@ function(add_entrypoint_object target_name) if(NOT ADD_ENTRYPOINT_OBJ_HDRS) message(FATAL_ERROR "`add_entrypoint_object` rule requires HDRS to be specified.") endif() + if(NOT ADD_ENTRYPOINT_OBJ_CXX_STANDARD) + set(ADD_ENTRYPOINT_OBJ_CXX_STANDARD ${CMAKE_CXX_STANDARD}) + endif() _get_common_compile_options(common_compile_options ${ADD_ENTRYPOINT_OBJ_COMPILE_OPTIONS}) set(internal_target_name ${fq_target_name}.__internal__) @@ -175,6 +282,15 @@ function(add_entrypoint_object target_name) get_fq_deps_list(fq_deps_list ${ADD_ENTRYPOINT_OBJ_DEPENDS}) set(full_deps_list ${fq_deps_list} libc.src.__support.common) + if(SHOW_INTERMEDIATE_OBJECTS) + message(STATUS "Adding entrypoint object ${fq_target_name}") + if(${SHOW_INTERMEDIATE_OBJECTS} STREQUAL "DEPS") + foreach(dep IN LISTS ADD_OBJECT_DEPENDS) + message(STATUS " ${fq_target_name} depends on ${dep}") + endforeach() + endif() + endif() + add_library( ${internal_target_name} # TODO: We don't need an object library for internal consumption. @@ -187,6 +303,12 @@ function(add_entrypoint_object target_name) target_compile_options(${internal_target_name} BEFORE PRIVATE ${common_compile_options}) target_include_directories(${internal_target_name} PRIVATE ${include_dirs}) add_dependencies(${internal_target_name} ${full_deps_list}) + set_target_properties( + ${internal_target_name} + PROPERTIES + CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD} + FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}" + ) add_library( ${fq_target_name} @@ -201,24 +323,18 @@ function(add_entrypoint_object target_name) target_include_directories(${fq_target_name} PRIVATE ${include_dirs}) add_dependencies(${fq_target_name} ${full_deps_list}) - if(ADD_ENTRYPOINT_OBJ_CXX_STANDARD) - set_target_properties( - ${fq_target_name} ${internal_target_name} - PROPERTIES - CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD} - ) - endif() - set_target_properties( ${fq_target_name} PROPERTIES - "ENTRYPOINT_NAME" ${entrypoint_name} - "TARGET_TYPE" ${ENTRYPOINT_OBJ_TARGET_TYPE} - "OBJECT_FILE" $<TARGET_OBJECTS:${fq_target_name}> + ENTRYPOINT_NAME ${ADD_ENTRYPOINT_OBJ_NAME} + TARGET_TYPE ${ENTRYPOINT_OBJ_TARGET_TYPE} + OBJECT_FILE "$<TARGET_OBJECTS:${fq_target_name}>" # TODO: We don't need to list internal object files if the internal # target is a normal static library. - "OBJECT_FILE_RAW" $<TARGET_OBJECTS:${internal_target_name}> - "DEPS" "${fq_deps_list}" + OBJECT_FILE_RAW "$<TARGET_OBJECTS:${internal_target_name}>" + CXX_STANDARD ${ADD_ENTRYPOINT_OBJ_CXX_STANDARD} + DEPS "${fq_deps_list}" + FLAGS "${ADD_ENTRYPOINT_OBJ_FLAGS}" ) if(LLVM_LIBC_ENABLE_LINTING) @@ -280,6 +396,105 @@ function(add_entrypoint_object target_name) ) endif() +endfunction(create_entrypoint_object) + +# Internal function, used by `add_entrypoint_object`. +function(expand_flags_for_entrypoint_object target_name flags) + cmake_parse_arguments( + "EXPAND_FLAGS" + "IGNORE_MARKER" # Optional arguments + "" # Single-value arguments + "DEPENDS;FLAGS" # Multi-value arguments + ${ARGN} + ) + + list(LENGTH flags nflags) + if(NOT ${nflags}) + create_entrypoint_object( + ${target_name} + DEPENDS ${EXPAND_FLAGS_DEPENDS} + FLAGS ${EXPAND_FLAGS_FLAGS} + ${EXPAND_FLAGS_UNPARSED_ARGUMENTS} + ) + return() + endif() + + list(POP_FRONT flags flag) + extract_flag_modifier(${flag} real_flag modifier) + + if(NOT "${modifier}" STREQUAL "NO") + expand_flags_for_entrypoint_object( + ${target_name} + "${flags}" + DEPENDS "${EXPAND_FLAGS_DEPENDS}" IGNORE_MARKER + FLAGS "${EXPAND_FLAGS_FLAGS}" IGNORE_MARKER + "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}" + ) + endif() + + if("${real_flag}" STREQUAL "" OR "${modifier}" STREQUAL "ONLY") + return() + endif() + + set(NEW_FLAGS ${EXPAND_FLAGS_FLAGS}) + list(REMOVE_ITEM NEW_FLAGS ${flag}) + get_fq_dep_list_without_flag(NEW_DEPS ${real_flag} ${EXPAND_FLAGS_DEPENDS}) + + # Only target with `flag` has `.__NO_flag` target, `flag__NO` and + # `flag__ONLY` do not. + if(NOT "${modifier}") + set(TARGET_NAME "${target_name}.__NO_${flag}") + else() + set(TARGET_NAME "${target_name}") + endif() + + expand_flags_for_entrypoint_object( + ${TARGET_NAME} + "${flags}" + DEPENDS "${NEW_DEPS}" IGNORE_MARKER + FLAGS "${NEW_FLAGS}" IGNORE_MARKER + "${EXPAND_FLAGS_UNPARSED_ARGUMENTS}" + ) +endfunction(expand_flags_for_entrypoint_object) + +function(add_entrypoint_object target_name) + cmake_parse_arguments( + "ADD_TO_EXPAND" + "" # Optional arguments + "NAME" # Single value arguments + "DEPENDS;FLAGS" # Multi-value arguments + ${ARGN} + ) + + get_fq_target_name(${target_name} fq_target_name) + + if(ADD_TO_EXPAND_DEPENDS AND ("${SHOW_INTERMEDIATE_OBJECTS}" STREQUAL "DEPS")) + message(STATUS "Gathering FLAGS from dependencies for ${fq_target_name}") + endif() + + get_fq_deps_list(fq_deps_list ${ADD_TO_EXPAND_DEPENDS}) + get_flags_from_dep_list(deps_flag_list ${fq_deps_list}) + + list(APPEND ADD_TO_EXPAND_FLAGS ${deps_flag_list}) + remove_duplicated_flags("${ADD_TO_EXPAND_FLAGS}" flags) + list(SORT flags) + + if(SHOW_INTERMEDIATE_OBJECTS AND flags) + message(STATUS "Object library ${fq_target_name} has FLAGS: ${flags}") + endif() + + if(NOT ADD_TO_EXPAND_NAME) + set(ADD_TO_EXPAND_NAME ${target_name}) + endif() + + expand_flags_for_entrypoint_object( + ${fq_target_name} + "${flags}" + NAME ${ADD_TO_EXPAND_NAME} IGNORE_MARKER + DEPENDS "${fq_deps_list}" IGNORE_MARKER + FLAGS "${flags}" IGNORE_MARKER + ${ADD_TO_EXPAND_UNPARSED_ARGUMENTS} + ) endfunction(add_entrypoint_object) set(ENTRYPOINT_EXT_TARGET_TYPE "ENTRYPOINT_EXT") |