diff --git a/Tests/RunCMake/AutoExportDll/AutoExport.cmake b/Tests/RunCMake/AutoExportDll/AutoExport.cmake index 8abf7fd4ab..8cd5809d5a 100644 --- a/Tests/RunCMake/AutoExportDll/AutoExport.cmake +++ b/Tests/RunCMake/AutoExportDll/AutoExport.cmake @@ -4,9 +4,21 @@ project(autoexport) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${autoexport_BINARY_DIR}/bin) add_subdirectory(sub) + add_library(objlib OBJECT objlib.c) set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1) -add_library(autoexport SHARED hello.cxx world.cxx foo.c $) + +add_library(objlib_maybe_lto OBJECT objlib_maybe_lto.c) +set_property(TARGET objlib_maybe_lto PROPERTY POSITION_INDEPENDENT_CODE 1) +# Automatic export definition generation for LTO objects is currently only +# supported with Clang targeting the MSVC ABI. +if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "Clang") + set_property(TARGET objlib_maybe_lto PROPERTY INTERPROCEDURAL_OPTIMIZATION ON) +endif() + +add_library(autoexport SHARED hello.cxx world.cxx foo.c) +target_link_libraries(autoexport PRIVATE objlib objlib_maybe_lto) + add_library(autoexport3 SHARED cppCLI.cxx) if(MSVC AND NOT MSVC_VERSION VERSION_LESS 1600 AND NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64") @@ -18,11 +30,16 @@ if(MSVC) set_target_properties(say PROPERTIES ENABLE_EXPORTS ON) add_library(autoexport_for_exec SHARED hello2.c) target_link_libraries(autoexport_for_exec say) - if(NOT MSVC_VERSION VERSION_LESS 1600 AND - NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64") - enable_language(ASM_MASM) - target_sources(autoexport PRIVATE nop.asm) - set_property(SOURCE nop.asm PROPERTY COMPILE_FLAGS /safeseh) + + if(NOT MSVC_VERSION VERSION_LESS 1600) + if(CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64") + enable_language(ASM_MARMASM) + target_sources(autoexport PRIVATE nop_ARM64.asm) + set_property(SOURCE nop_ARM64.asm PROPERTY VS_SETTINGS "PreprocessWithCl=false") + else() + enable_language(ASM_MASM) + target_sources(autoexport PRIVATE nop_x64.asm) + endif() target_compile_definitions(say PRIVATE HAS_JUSTNOP) endif() endif() diff --git a/Tests/RunCMake/AutoExportDll/AutoExportShort.cmake b/Tests/RunCMake/AutoExportDll/AutoExportShort.cmake index 08ee5d467e..caf49a4b0a 100644 --- a/Tests/RunCMake/AutoExportDll/AutoExportShort.cmake +++ b/Tests/RunCMake/AutoExportDll/AutoExportShort.cmake @@ -4,9 +4,21 @@ project(autoexport) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${autoexport_BINARY_DIR}/bin) add_subdirectory(sub) + add_library(objlib OBJECT objlib.c) set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1) -add_library(autoexport SHARED hello.cxx world.cxx foo.c $) + +add_library(objlib_maybe_lto OBJECT objlib_maybe_lto.c) +set_property(TARGET objlib_maybe_lto PROPERTY POSITION_INDEPENDENT_CODE 1) +# Automatic export definition generation for LTO objects is currently only +# supported with Clang targeting the MSVC ABI. +if(MSVC AND CMAKE_C_COMPILER_ID STREQUAL "Clang") + set_property(TARGET objlib_maybe_lto PROPERTY INTERPROCEDURAL_OPTIMIZATION ON) +endif() + +add_library(autoexport SHARED hello.cxx world.cxx foo.c) +target_link_libraries(autoexport PRIVATE objlib objlib_maybe_lto) + add_library(autoexport3 SHARED cppCLI.cxx) if(MSVC AND NOT MSVC_VERSION VERSION_LESS 1600 AND NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64") @@ -18,11 +30,16 @@ if(MSVC) set_target_properties(say PROPERTIES ENABLE_EXPORTS ON) add_library(autoexport_for_exec SHARED hello2.c) target_link_libraries(autoexport_for_exec say) - if(NOT MSVC_VERSION VERSION_LESS 1600 AND - NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64") - enable_language(ASM_MASM) - target_sources(autoexport PRIVATE nop.asm) - set_property(SOURCE nop.asm PROPERTY COMPILE_FLAGS /safeseh) + + if(NOT MSVC_VERSION VERSION_LESS 1600) + if(CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64") + enable_language(ASM_MARMASM) + target_sources(autoexport PRIVATE nop_ARM64.asm) + set_property(SOURCE nop_ARM64.asm PROPERTY VS_SETTINGS "PreprocessWithCl=false") + else() + enable_language(ASM_MASM) + target_sources(autoexport PRIVATE nop_x64.asm) + endif() target_compile_definitions(say PRIVATE HAS_JUSTNOP) endif() endif() diff --git a/Tests/RunCMake/AutoExportDll/nop_ARM64.asm b/Tests/RunCMake/AutoExportDll/nop_ARM64.asm new file mode 100644 index 0000000000..661bb3f7b4 --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/nop_ARM64.asm @@ -0,0 +1,8 @@ + AREA SOME, CODE, READONLY + + EXPORT justnop +justnop PROC + ret + ENDP + + END diff --git a/Tests/RunCMake/AutoExportDll/nop.asm b/Tests/RunCMake/AutoExportDll/nop_x64.asm similarity index 64% rename from Tests/RunCMake/AutoExportDll/nop.asm rename to Tests/RunCMake/AutoExportDll/nop_x64.asm index fd6892f5da..4ed575dfcb 100644 --- a/Tests/RunCMake/AutoExportDll/nop.asm +++ b/Tests/RunCMake/AutoExportDll/nop_x64.asm @@ -3,10 +3,11 @@ ELSE .MODEL FLAT,C ENDIF -SOME SEGMENT EXECUTE READ +.CODE public justnop -justnop: +justnop PROC ret +justnop ENDP END diff --git a/Tests/RunCMake/AutoExportDll/objlib_maybe_lto.c b/Tests/RunCMake/AutoExportDll/objlib_maybe_lto.c new file mode 100644 index 0000000000..7390cedd2b --- /dev/null +++ b/Tests/RunCMake/AutoExportDll/objlib_maybe_lto.c @@ -0,0 +1,4 @@ +int objlib_maybe_lto(void) +{ + return 8; +} diff --git a/Tests/RunCMake/AutoExportDll/say.cxx b/Tests/RunCMake/AutoExportDll/say.cxx index a9459a9b23..f93e775f39 100644 --- a/Tests/RunCMake/AutoExportDll/say.cxx +++ b/Tests/RunCMake/AutoExportDll/say.cxx @@ -13,6 +13,7 @@ int WINAPI foo(); // test regular C int bar(); int objlib(); +int objlib_maybe_lto(); void justnop(); } @@ -45,6 +46,9 @@ int main() printf("\n"); bar(); objlib(); + if (objlib_maybe_lto() != 8) { + return 1; + } printf("\n"); cliFunction(); printf("\n"); diff --git a/Tests/RunCMake/CommandLine/.gitattributes b/Tests/RunCMake/CommandLine/.gitattributes index b0b0588cb3..c1c17f476f 100644 --- a/Tests/RunCMake/CommandLine/.gitattributes +++ b/Tests/RunCMake/CommandLine/.gitattributes @@ -1,2 +1,3 @@ E_cat_binary_files/binary.obj -text E_cat_good_binary_cat-stdout.txt -text -whitespace +E___create_def-nm-*-expected.def whitespace=-blank-at-eol diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-check.cmake b/Tests/RunCMake/CommandLine/E___create_def-nm-check.cmake new file mode 100644 index 0000000000..f11242fa68 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-check.cmake @@ -0,0 +1,9 @@ +string(REGEX REPLACE [[^E___create_def-nm-]] "" subtest "${test}") +cmake_path(APPEND RunCMake_TEST_BINARY_DIR "${subtest}.def" OUTPUT_VARIABLE actual_def) +cmake_path(APPEND RunCMake_TEST_SOURCE_DIR "${test}-expected.def" OUTPUT_VARIABLE expected_def) +execute_process( + COMMAND ${CMAKE_COMMAND} -E compare_files --ignore-eol ${actual_def} ${expected_def} + RESULT_VARIABLE compare_result) +if(compare_result) + set(RunCMake_TEST_FAILED "${actual_def} does not match ${expected_def}") +endif() diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-mixed-expected.def b/Tests/RunCMake/CommandLine/E___create_def-nm-mixed-expected.def new file mode 100644 index 0000000000..35f1a379ae --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-mixed-expected.def @@ -0,0 +1,3 @@ +EXPORTS + manual + mixed diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-multiple-expected.def b/Tests/RunCMake/CommandLine/E___create_def-nm-multiple-expected.def new file mode 100644 index 0000000000..535cf81c3e --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-multiple-expected.def @@ -0,0 +1,3 @@ +EXPORTS + first + second diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-not-found-result.txt b/Tests/RunCMake/CommandLine/E___create_def-nm-not-found-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-not-found-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-not-found-stderr.txt b/Tests/RunCMake/CommandLine/E___create_def-nm-not-found-stderr.txt new file mode 100644 index 0000000000..6095b39b2b --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-not-found-stderr.txt @@ -0,0 +1,2 @@ +^cmake-nm-does-not-exist returned an error: [^ +]* diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-single-expected.def b/Tests/RunCMake/CommandLine/E___create_def-nm-single-expected.def new file mode 100644 index 0000000000..26c70ebdc3 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-single-expected.def @@ -0,0 +1,2 @@ +EXPORTS + single diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-spaces-expected.def b/Tests/RunCMake/CommandLine/E___create_def-nm-spaces-expected.def new file mode 100644 index 0000000000..59967c9ec7 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-spaces-expected.def @@ -0,0 +1,2 @@ +EXPORTS + spaced diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-symbol-types-expected.def b/Tests/RunCMake/CommandLine/E___create_def-nm-symbol-types-expected.def new file mode 100644 index 0000000000..9c8b05507a --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-symbol-types-expected.def @@ -0,0 +1,6 @@ +EXPORTS + ??_7Example@@6B@ DATA + bss DATA + common DATA + data DATA + text diff --git a/Tests/RunCMake/CommandLine/E___create_def-nm-symbol-types-stderr.txt b/Tests/RunCMake/CommandLine/E___create_def-nm-symbol-types-stderr.txt new file mode 100644 index 0000000000..3e2b48b153 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def-nm-symbol-types-stderr.txt @@ -0,0 +1 @@ +^Ignoring symbol 'unknown' with unrecognized type '\?' in object 'symbol-types.obj'\.$ diff --git a/Tests/RunCMake/CommandLine/E___create_def.cmake b/Tests/RunCMake/CommandLine/E___create_def.cmake new file mode 100644 index 0000000000..46194a2c17 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E___create_def.cmake @@ -0,0 +1,42 @@ +string(ASCII 66 67 192 222 llvm_bitcode_magic) +string(REPEAT "x" 64 llvm_bitcode_padding) +file(WRITE "${CMAKE_BINARY_DIR}/bitcode.obj" + "${llvm_bitcode_magic}${llvm_bitcode_padding}") +file(WRITE "${CMAKE_BINARY_DIR}/nm-not-found.objs" [[ +bitcode.obj +]]) + +file(WRITE "${CMAKE_BINARY_DIR}/single.obj" "") +file(WRITE "${CMAKE_BINARY_DIR}/single.objs" [[ +single.obj +]]) + +file(WRITE "${CMAKE_BINARY_DIR}/symbol-types.obj" "") +file(WRITE "${CMAKE_BINARY_DIR}/symbol-types.objs" [[ +symbol-types.obj +]]) + +file(WRITE "${CMAKE_BINARY_DIR}/first.obj" "") +file(WRITE "${CMAKE_BINARY_DIR}/no-symbols.obj" "") +file(WRITE "${CMAKE_BINARY_DIR}/second.obj" "") +file(WRITE "${CMAKE_BINARY_DIR}/multiple.objs" [[ +first.obj +no-symbols.obj +second.obj +]]) + +file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/directory with spaces") +file(WRITE "${CMAKE_BINARY_DIR}/directory with spaces/spaced.obj" "") +file(WRITE "${CMAKE_BINARY_DIR}/spaces.objs" [[ +directory with spaces/spaced.obj +]]) + +file(WRITE "${CMAKE_BINARY_DIR}/manual.def" [[ +EXPORTS + manual +]]) +file(WRITE "${CMAKE_BINARY_DIR}/mixed.obj" "") +file(WRITE "${CMAKE_BINARY_DIR}/mixed.objs" [[ +manual.def +mixed.obj +]]) diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 9dd39dce72..d309f705fe 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -87,6 +87,26 @@ run_cmake_command(E___run_co_compile-no--- ${CMAKE_COMMAND} -E __run_co_compile run_cmake_command(E___run_co_compile-no-cc ${CMAKE_COMMAND} -E __run_co_compile --iwyu=iwyu-does-not-exist --) run_cmake_command(E___run_co_compile-tidy-remove-fixes ${CMAKE_COMMAND} -E __run_co_compile "--tidy=${CMAKE_COMMAND}\\;-E\\;true\\;--export-fixes=${RunCMake_BINARY_DIR}/tidy-fixes.yaml" -- ${CMAKE_COMMAND} -E true) +block() + set(RunCMake_TEST_BINARY_DIR + ${RunCMake_BINARY_DIR}/E___create_def-build) + run_cmake(E___create_def) + set(RunCMake_TEST_NO_CLEAN 1) + + # bitcode.obj contains LLVM bitcode magic followed by padding. + run_cmake_command(E___create_def-nm-not-found ${CMAKE_COMMAND} -E __create_def nm-not-found.def nm-not-found.objs --nm=cmake-nm-does-not-exist) + + if(CMAKE_HOST_UNIX) + set(fake_nm ${RunCMake_SOURCE_DIR}/fake-nm.sh) + set(RunCMake-check-file E___create_def-nm-check.cmake) + run_cmake_command(E___create_def-nm-single ${CMAKE_COMMAND} -E __create_def single.def single.objs --nm=${fake_nm}) + run_cmake_command(E___create_def-nm-symbol-types ${CMAKE_COMMAND} -E __create_def symbol-types.def symbol-types.objs --nm=${fake_nm}) + run_cmake_command(E___create_def-nm-multiple ${CMAKE_COMMAND} -E __create_def multiple.def multiple.objs --nm=${fake_nm}) + run_cmake_command(E___create_def-nm-spaces ${CMAKE_COMMAND} -E __create_def spaces.def spaces.objs --nm=${fake_nm}) + run_cmake_command(E___create_def-nm-mixed ${CMAKE_COMMAND} -E __create_def mixed.def mixed.objs --nm=${fake_nm}) + endif() +endblock() + block() set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/list-cache-build) run_cmake(list-cache) diff --git a/Tests/RunCMake/CommandLine/fake-nm.sh b/Tests/RunCMake/CommandLine/fake-nm.sh new file mode 100755 index 0000000000..f6ef2a7ac8 --- /dev/null +++ b/Tests/RunCMake/CommandLine/fake-nm.sh @@ -0,0 +1,122 @@ +#!/bin/sh + +set -eu + +if test "$#" -eq 4 && + test "$1" = "--no-weak" && + test "$2" = "--defined-only" && + test "$3" = "--format=posix"; then + print_file_name=0 + input=$4 +elif test "$#" -eq 5 && + test "$1" = "--no-weak" && + test "$2" = "--defined-only" && + test "$3" = "--format=posix" && + test "$4" = "--print-file-name"; then + print_file_name=1 + input=$5 +else + echo "unexpected nm arguments: $*" >&2 + exit 1 +fi + +pending_symbol=0 + +finish_symbol() +{ + if test "${pending_symbol}" -eq 1; then + printf ' 0 0\r\n' + pending_symbol=0 + fi +} + +start_symbol() +{ + finish_symbol + if test "${print_file_name}" -eq 1; then + printf '%s: %s %s' "$1" "$2" "$3" + else + printf '%s %s' "$2" "$3" + fi + pending_symbol=1 +} + +process_object() +{ + object=$1 + case "${object}" in + \"*\") + object=${object#\"} + object=${object%\"} + ;; + esac + + case "${object}" in + *single.obj) + start_symbol "${object}" single T + ;; + *symbol-types.obj) + start_symbol "${object}" absolute A + start_symbol "${object}" bss B + start_symbol "${object}" common C + start_symbol "${object}" data D + start_symbol "${object}" import I + start_symbol "${object}" debug N + start_symbol "${object}" readonly R + start_symbol "${object}" '??_7Example@@6B@' R + start_symbol "${object}" '??_R4Example@@6B@' R + start_symbol "${object}" section S + start_symbol "${object}" text T + start_symbol "${object}" undefined U + start_symbol "${object}" weak_object V + start_symbol "${object}" weak W + start_symbol "${object}" local_absolute a + start_symbol "${object}" local_bss b + start_symbol "${object}" local_common c + start_symbol "${object}" local_data d + start_symbol "${object}" local_import i + start_symbol "${object}" local_debug n + start_symbol "${object}" local_readonly r + start_symbol "${object}" local_section s + start_symbol "${object}" local_text t + start_symbol "${object}" local_weak_object v + start_symbol "${object}" local_weak w + start_symbol "${object}" unknown '?' + ;; + *first.obj) + start_symbol "${object}" first T + ;; + *no-symbols.obj) + sleep 0.1 + printf '%s: no symbols\n' "${object}" >&2 + sleep 0.1 + finish_symbol + ;; + *second.obj) + start_symbol "${object}" second T + ;; + *spaced.obj) + start_symbol "${object}" spaced T + ;; + *mixed.obj) + start_symbol "${object}" mixed T + ;; + *) + echo "unexpected nm input: ${object}" >&2 + exit 1 + ;; + esac +} + +case "${input}" in + @*) + response=${input#@} + while IFS= read -r object || test -n "${object}"; do + process_object "${object}" + done < "${response}" + ;; + *) + process_object "${input}" + ;; +esac +finish_symbol diff --git a/Tests/RunCMake/VS10Project/AutoExportNm-check.cmake b/Tests/RunCMake/VS10Project/AutoExportNm-check.cmake new file mode 100644 index 0000000000..e454a30253 --- /dev/null +++ b/Tests/RunCMake/VS10Project/AutoExportNm-check.cmake @@ -0,0 +1,24 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/AutoExportNm.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED + "Project file ${vcProjectFile} does not exist.") + return() +endif() + +file(READ "${vcProjectFile}" vcProject) +file(READ "${RunCMake_TEST_BINARY_DIR}/platform-toolset.txt" + platformToolset) +if(platformToolset MATCHES [[^[Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?$]] OR + platformToolset MATCHES [[^[Cc][Ll][Aa][Nn][Gg]([Cc][Ll]$|_[0-9])]]) + if(NOT vcProject MATCHES + [[__create_def[^<]*--nm=C:/cmake-nm-test/tool-nm\.exe]]) + set(RunCMake_TEST_FAILED + "__create_def does not pass CMAKE_NM in ${vcProjectFile}.") + endif() +else() + if(vcProject MATCHES + [[__create_def[^<]*--nm=C:/cmake-nm-test/tool-nm\.exe]]) + set(RunCMake_TEST_FAILED + "__create_def passes CMAKE_NM for toolset ${platformToolset}.") + endif() +endif() diff --git a/Tests/RunCMake/VS10Project/AutoExportNm.cmake b/Tests/RunCMake/VS10Project/AutoExportNm.cmake new file mode 100644 index 0000000000..7e6e4cd479 --- /dev/null +++ b/Tests/RunCMake/VS10Project/AutoExportNm.cmake @@ -0,0 +1,11 @@ +enable_language(C) + +set(CMAKE_NM "C:/cmake-nm-test/tool-nm.exe") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/platform-toolset.txt" + "${CMAKE_VS_PLATFORM_TOOLSET}") + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/AutoExportNm.c" + "void auto_export_nm(void) {}\n") +add_library(AutoExportNm SHARED + "${CMAKE_CURRENT_BINARY_DIR}/AutoExportNm.c") +set_property(TARGET AutoExportNm PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON) diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index d7a4d72462..06b148e514 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -5,6 +5,7 @@ if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREA endif() run_cmake(CustomCommandGenex) +run_cmake(AutoExportNm) if(NOT RunCMake_GENERATOR MATCHES "^Visual Studio 1[1-5] ") run_cmake(CustomCommandParallel) run_cmake(CustomCommandParallelDisable)