cmake: use assembly language support This commit moves the asm libraries to object libraries through CMake's ASM and ASM_NASM support. It brings the following benefits: - we no longer need to duplicate between static and shared libraries - Nasm objects can now be fully compiled in parallel (as they're not custom targets anymore) - there's no longer the need for dummy C files to determine the linker The ASM language support is currently unused, but it's been added since AS_EXECUTABLE was used for both Nasm and GAS files. For Xcode, the existing approach has to be preserved due to the following issues: - the Xcode generator does not recognise ASM_NASM as a valid language, so it does not output build rules - even if this was fixed (with explicitFileType set to "sourcecode.nasm"), the default build rule in Xcode does not carry any of the ASM_NASM flags, nor the selected object format These issues were already detected in [1], and I asked about them in the CMake Discourse forum [2], to no avail yet. Since this change relies on CMake's CheckLanguage module and ASM_NASM language support, the minimum version has been increased to 3.9. [1]: https://cmake.org/pipermail/cmake/2018-October/068332.html [2]: https://discourse.cmake.org/t/building-nasm-files-with-xcode/7934 Related: aomedia:3401 Change-Id: Id0d4c8208afa403df30c0b8ab9b0809e6d67d6d8
diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e38010..50c4efd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -11,7 +11,7 @@ if(CONFIG_TFLITE) cmake_minimum_required(VERSION 3.11) else() - cmake_minimum_required(VERSION 3.7) + cmake_minimum_required(VERSION 3.9) endif() set(AOM_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
diff --git a/aom_ports/aom_ports.cmake b/aom_ports/aom_ports.cmake index 92d3030..e3b67e4 100644 --- a/aom_ports/aom_ports.cmake +++ b/aom_ports/aom_ports.cmake
@@ -49,9 +49,13 @@ # # * The libaom target must exist before this function is called. function(setup_aom_ports_targets) - if(WIN32 AND "${AOM_TARGET_CPU}" STREQUAL "x86_64") + if(XCODE AND "${AOM_TARGET_CPU}" STREQUAL "x86_64") add_asm_library("aom_ports" "AOM_PORTS_ASM_X86") - set(aom_ports_asm_lib 1) + # Xcode is the only one + set(aom_ports_is_embedded 1) + set(aom_ports_has_symbols 1) + elseif(WIN32 AND "${AOM_TARGET_CPU}" STREQUAL "x86_64") + add_asm_library("aom_ports" "AOM_PORTS_ASM_X86") set(aom_ports_has_symbols 1) elseif("${AOM_TARGET_CPU}" MATCHES "arm") add_library(aom_ports OBJECT ${AOM_PORTS_SOURCES_ARM}) @@ -74,14 +78,7 @@ # libaom_srcs.*; if it becomes necessary for a particular generator another # method should be used. if(aom_ports_has_symbols) - if(aom_ports_asm_lib) - # When aom_ports is an asm library its name changes based on build - # configuration. This handles adding sources to the correct target(s). - target_sources(aom_ports_static PRIVATE ${AOM_PORTS_INCLUDES}) - if(BUILD_SHARED_LIBS) - target_sources(aom_ports_shared PRIVATE ${AOM_PORTS_INCLUDES}) - endif() - else() + if(NOT aom_ports_is_embedded) target_sources(aom_ports PRIVATE ${AOM_PORTS_INCLUDES}) endif() set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE)
diff --git a/build/cmake/aom_configure.cmake b/build/cmake/aom_configure.cmake index d5fa169..33def6c 100644 --- a/build/cmake/aom_configure.cmake +++ b/build/cmake/aom_configure.cmake
@@ -155,49 +155,61 @@ endif() if(AOM_TARGET_CPU STREQUAL "x86" OR AOM_TARGET_CPU STREQUAL "x86_64") - find_program(AS_EXECUTABLE yasm $ENV{YASM_PATH}) - if(NOT AS_EXECUTABLE OR ENABLE_NASM) - unset(AS_EXECUTABLE CACHE) - find_program(AS_EXECUTABLE nasm $ENV{NASM_PATH}) - if(AS_EXECUTABLE) - test_nasm() - endif() + find_program(CMAKE_ASM_NASM_COMPILER yasm $ENV{YASM_PATH}) + if(NOT CMAKE_ASM_NASM_COMPILER OR ENABLE_NASM) + unset(CMAKE_ASM_NASM_COMPILER CACHE) + find_program(CMAKE_ASM_NASM_COMPILER nasm $ENV{NASM_PATH}) endif() - if(NOT AS_EXECUTABLE) + include(CheckLanguage) + check_language(ASM_NASM) + if(CMAKE_ASM_NASM_COMPILER) + get_asm_obj_format("objformat") + unset(CMAKE_ASM_NASM_OBJECT_FORMAT) + set(CMAKE_ASM_NASM_OBJECT_FORMAT ${objformat}) + enable_language(ASM_NASM) + if(CMAKE_ASM_NASM_COMPILER_ID STREQUAL "NASM") + test_nasm() + endif() + # Xcode requires building the objects manually, so pass the object format + # flag. + if(XCODE) + set(AOM_AS_FLAGS -f ${objformat} ${AOM_AS_FLAGS}) + endif() + else() message( FATAL_ERROR "Unable to find assembler. Install 'yasm' or 'nasm.' " "To build without optimizations, add -DAOM_TARGET_CPU=generic to " "your cmake command line.") endif() - get_asm_obj_format("objformat") - set(AOM_AS_FLAGS -f ${objformat} ${AOM_AS_FLAGS}) string(STRIP "${AOM_AS_FLAGS}" AOM_AS_FLAGS) elseif(AOM_TARGET_CPU MATCHES "arm") if(AOM_TARGET_SYSTEM STREQUAL "Darwin") - set(AS_EXECUTABLE as) + set(CMAKE_ASM_COMPILER as) set(AOM_AS_FLAGS -arch ${AOM_TARGET_CPU} -isysroot ${CMAKE_OSX_SYSROOT}) elseif(AOM_TARGET_SYSTEM STREQUAL "Windows") - if(NOT AS_EXECUTABLE) - set(AS_EXECUTABLE ${CMAKE_C_COMPILER} -c -mimplicit-it=always) + if(NOT CMAKE_ASM_COMPILER) + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER} -c -mimplicit-it=always) endif() else() - if(NOT AS_EXECUTABLE) - set(AS_EXECUTABLE as) + if(NOT CMAKE_ASM_COMPILER) + set(CMAKE_ASM_COMPILER as) endif() endif() - find_program(as_executable_found ${AS_EXECUTABLE}) - if(NOT as_executable_found) + include(CheckLanguage) + check_language(ASM) + if(NOT CMAKE_ASM_COMPILER) message( FATAL_ERROR "Unable to find assembler and optimizations are enabled." - "Searched for ${AS_EXECUTABLE}. Install it, add it to your path, or " - "set the assembler directly by adding -DAS_EXECUTABLE=<assembler path> " - "to your CMake command line." + "Searched for ${CMAKE_ASM_COMPILER}. Install it, add it to your path," + "or set the assembler directly by adding " + "-DCMAKE_ASM_COMPILER=<assembler path> to your CMake command line." "To build without optimizations, add -DAOM_TARGET_CPU=generic to your " "cmake command line.") endif() + enable_language(ASM) string(STRIP "${AOM_AS_FLAGS}" AOM_AS_FLAGS) endif()
diff --git a/build/cmake/aom_optimization.cmake b/build/cmake/aom_optimization.cmake index ff0193a..f8eeb82 100644 --- a/build/cmake/aom_optimization.cmake +++ b/build/cmake/aom_optimization.cmake
@@ -133,7 +133,7 @@ # language, and that build tools don't complain that an object exposes no # symbols. # -# In shared library configs every step described above happens twice, and +# In Xcode-based builds every step described above happens twice, and # directory/target/object names are updated to include _shared and _static # suffixes. function(add_asm_library lib_name asm_sources) @@ -141,49 +141,66 @@ return() endif() - list(APPEND asm_configs "static") - if(BUILD_SHARED_LIBS) - list(APPEND asm_configs "shared") - endif() - - foreach(asm_config ${asm_configs}) - set(asm_lib_name ${lib_name}_${asm_config}) - set(asm_lib_obj_dir "${AOM_CONFIG_DIR}/asm_objects/${asm_lib_name}") - if(NOT EXISTS "${asm_lib_obj_dir}") - file(MAKE_DIRECTORY "${asm_lib_obj_dir}") + if(XCODE) + # CMake's generator does not output a build rule for Nasm files. Moreover, + # it makes Xcode believe Nasm files are of type "sourcecode" instead of + # "sourcecode.nasm", which prevents even the default rule from applying. + # This default rule is broken, though, because it doesn't apply any of the + # flags specified for ASM_NASM. See https://discourse.cmake.org/t/building- + # nasm-files-with-xcode/7934 + list(APPEND asm_configs "static") + if(BUILD_SHARED_LIBS) + list(APPEND asm_configs "shared") endif() - add_library(${asm_lib_name} STATIC ${${asm_sources}}) - set_property(TARGET ${asm_lib_name} PROPERTY FOLDER ${AOM_TARGET_CPU}) + set(as_executable "${CMAKE_ASM_NASM_COMPILER}") + if(NOT as_executable) + set(as_executable "${CMAKE_ASM_COMPILER}") + endif() - foreach(asm_source ${${asm_sources}}) - get_filename_component(asm_source_name "${asm_source}" NAME) - set(asm_object "${asm_lib_obj_dir}/${asm_source_name}.o") - add_custom_command(OUTPUT "${asm_object}" - COMMAND ${AS_EXECUTABLE} ARGS ${AOM_AS_FLAGS} - -I${AOM_ROOT}/ -I${AOM_CONFIG_DIR}/ -o - "${asm_object}" "${asm_source}" - DEPENDS "${asm_source}" - COMMENT "Building ASM object ${asm_object}" - WORKING_DIRECTORY "${AOM_CONFIG_DIR}" - VERBATIM) - if(BUILD_SHARED_LIBS AND "${asm_config}" STREQUAL "static") - target_sources(aom_static PRIVATE "${asm_object}") - else() - target_sources(aom PRIVATE "${asm_object}") + foreach(asm_config ${asm_configs}) + set(asm_lib_name ${lib_name}_${asm_config}) + set(asm_lib_obj_dir "${AOM_CONFIG_DIR}/asm_objects/${asm_lib_name}") + if(NOT EXISTS "${asm_lib_obj_dir}") + file(MAKE_DIRECTORY "${asm_lib_obj_dir}") endif() - endforeach() - # The above created a target containing only ASM sources. CMake needs help - # here to determine the linker language. Add a C file with an unused no-op - # function to force the linker language to C. We don't bother with setting - # the LINKER_LANGUAGE property on the library target because not all - # generators obey it (looking at you, Xcode generator). - add_no_op_source_file_to_target("${asm_lib_name}" "c") + foreach(asm_source ${${asm_sources}}) + get_filename_component(asm_source_name "${asm_source}" NAME) + set(asm_object "${asm_lib_obj_dir}/${asm_source_name}.o") + add_custom_command(OUTPUT "${asm_object}" + COMMAND ${as_executable} ARGS ${AOM_AS_FLAGS} + -I${AOM_ROOT}/ -I${AOM_CONFIG_DIR}/ -o + "${asm_object}" "${asm_source}" + DEPENDS "${asm_source}" + COMMENT "Building ASM object ${asm_object}" + WORKING_DIRECTORY "${AOM_CONFIG_DIR}" + VERBATIM) + if(BUILD_SHARED_LIBS AND "${asm_config}" STREQUAL "static") + target_sources(aom_static PRIVATE "${asm_object}") + else() + target_sources(aom PRIVATE "${asm_object}") + endif() + endforeach() + endforeach() + else() + # For non-Xcode generators, CMake does not need extra help. The language + # support takes care of it. + set(asm_lib_name ${lib_name}) + + add_library(${asm_lib_name} OBJECT ${${asm_sources}}) + target_include_directories(${asm_lib_name} + PRIVATE ${AOM_ROOT} ${AOM_CONFIG_DIR}) + target_compile_options(${asm_lib_name} PRIVATE ${AOM_AS_FLAGS}) + set_property(TARGET ${asm_lib_name} PROPERTY FOLDER ${AOM_TARGET_CPU}) + if(BUILD_SHARED_LIBS) + target_sources(aom_static PRIVATE "$<TARGET_OBJECTS:${asm_lib_name}>") + endif() + target_sources(aom PRIVATE "$<TARGET_OBJECTS:${asm_lib_name}>") # Add the new lib target to the global list of aom library targets. list(APPEND AOM_LIB_TARGETS ${asm_lib_name}) - endforeach() + endif() set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE) endfunction() @@ -192,7 +209,8 @@ # Currently checks only for presence of required object formats and support for # the -Ox argument (multipass optimization). function(test_nasm) - execute_process(COMMAND ${AS_EXECUTABLE} -hf OUTPUT_VARIABLE nasm_helptext) + execute_process(COMMAND ${CMAKE_ASM_NASM_COMPILER} -hf + OUTPUT_VARIABLE nasm_helptext) if(NOT "${nasm_helptext}" MATCHES "-Ox") message(
diff --git a/build/cmake/toolchains/android.cmake b/build/cmake/toolchains/android.cmake index f0b9fab..4d38c9a 100644 --- a/build/cmake/toolchains/android.cmake +++ b/build/cmake/toolchains/android.cmake
@@ -45,11 +45,11 @@ endif() if(ANDROID_ABI MATCHES "^arm") - set(AS_EXECUTABLE as) + set(CMAKE_ASM_COMPILER as) # No runtime cpu detect for arm targets. set(CONFIG_RUNTIME_CPU_DETECT 0 CACHE STRING "") elseif(ANDROID_ABI MATCHES "^x86") - set(AS_EXECUTABLE yasm) + set(CMAKE_ASM_NASM_COMPILER yasm) endif() set(CMAKE_SYSTEM_NAME "Android")
diff --git a/build/cmake/toolchains/arm64-linux-gcc.cmake b/build/cmake/toolchains/arm64-linux-gcc.cmake index 64e460b..a510524 100644 --- a/build/cmake/toolchains/arm64-linux-gcc.cmake +++ b/build/cmake/toolchains/arm64-linux-gcc.cmake
@@ -27,8 +27,8 @@ if(NOT CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER ${CROSS}g++) endif() -if(NOT AS_EXECUTABLE) - set(AS_EXECUTABLE ${CROSS}as) +if(NOT CMAKE_ASM_COMPILER) + set(CMAKE_ASM_COMPILER ${CROSS}as) endif() set(CMAKE_C_FLAGS_INIT "-march=armv8-a") set(CMAKE_CXX_FLAGS_INIT "-march=armv8-a")
diff --git a/build/cmake/toolchains/armv7-linux-gcc.cmake b/build/cmake/toolchains/armv7-linux-gcc.cmake index 1201538..7ce1dd8 100644 --- a/build/cmake/toolchains/armv7-linux-gcc.cmake +++ b/build/cmake/toolchains/armv7-linux-gcc.cmake
@@ -31,8 +31,8 @@ if(NOT CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER ${CROSS}g++) endif() -if(NOT AS_EXECUTABLE) - set(AS_EXECUTABLE ${CROSS}as) +if(NOT CMAKE_ASM_COMPILER) + set(CMAKE_ASM_COMPILER ${CROSS}as) endif() set(CMAKE_C_FLAGS_INIT "-march=armv7-a -mfpu=vfpv3 \ ${AOM_EXTRA_TOOLCHAIN_FLAGS}")
diff --git a/build/cmake/toolchains/ppc-linux-gcc.cmake b/build/cmake/toolchains/ppc-linux-gcc.cmake index ab0efea..aeb2420 100644 --- a/build/cmake/toolchains/ppc-linux-gcc.cmake +++ b/build/cmake/toolchains/ppc-linux-gcc.cmake
@@ -27,8 +27,8 @@ if(NOT CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER ${CROSS}g++) endif() -if(NOT AS_EXECUTABLE) - set(AS_EXECUTABLE ${CROSS}as) +if(NOT CMAKE_ASM_COMPILER) + set(CMAKE_ASM_COMPILER ${CROSS}as) endif() set(CMAKE_SYSTEM_PROCESSOR "ppc")
diff --git a/build/cmake/toolchains/riscv-linux-gcc.cmake b/build/cmake/toolchains/riscv-linux-gcc.cmake index 21e7370..65b7c59 100644 --- a/build/cmake/toolchains/riscv-linux-gcc.cmake +++ b/build/cmake/toolchains/riscv-linux-gcc.cmake
@@ -27,8 +27,8 @@ if(NOT CMAKE_CXX_COMPILER) set(CMAKE_CXX_COMPILER ${CROSS}g++) endif() -if(NOT AS_EXECUTABLE) - set(AS_EXECUTABLE ${CROSS}as) +if(NOT CMAKE_ASM_COMPILER) + set(CMAKE_ASM_COMPILER ${CROSS}as) endif() set(CMAKE_SYSTEM_PROCESSOR "riscv")