Skip to content

Commit 5ca626a

Browse files
authored
Add CMake build and a limited subset of tests for llvm-mingw (#1216)
1 parent b79565c commit 5ca626a

36 files changed

+516
-26
lines changed

.github/workflows/ci.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,53 @@ jobs:
273273
_build/${{ matrix.arch }}/${{ matrix.config }}/*.lib
274274
_build/${{ matrix.arch }}/${{ matrix.config }}/*.pdb
275275
276+
test-llvm-mingw-cppwinrt:
277+
name: 'llvm-mingw: Build and test'
278+
strategy:
279+
matrix:
280+
arch: [i686, x86_64]
281+
runs-on: windows-latest
282+
steps:
283+
- uses: actions/checkout@v3
284+
285+
- name: Install llvm-mingw toolchain
286+
run: |
287+
$llvm_mingw_version = "20220906"
288+
Invoke-WebRequest "https://github.com/mstorsjo/llvm-mingw/releases/download/${llvm_mingw_version}/llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}.zip" -OutFile llvm-mingw.zip
289+
7z x llvm-mingw.zip
290+
rm llvm-mingw.zip
291+
if (!(Test-Path "$pwd\llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}\bin\clang++.exe")) { return 1 }
292+
Add-Content $env:GITHUB_PATH "$pwd\llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}\bin"
293+
294+
- name: Build cppwinrt
295+
run: |
296+
mkdir build
297+
cd build
298+
cmake ../ -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug
299+
cmake --build . --target cppwinrt
300+
301+
- name: Upload cppwinrt.exe
302+
uses: actions/upload-artifact@v3
303+
with:
304+
name: llvm-mingw-build-${{ matrix.arch }}-bin
305+
path: build/cppwinrt.exe
306+
307+
- name: Build tests
308+
run: |
309+
cd build
310+
cmake --build . --target test-vanilla test_win7
311+
312+
- name: Upload test binaries
313+
uses: actions/upload-artifact@v3
314+
with:
315+
name: llvm-mingw-tests-${{ matrix.arch }}-bin
316+
path: build/test/*.exe
317+
318+
- name: Run tests
319+
run: |
320+
cd build
321+
ctest --verbose
322+
276323
build-msvc-natvis:
277324
name: 'Build natvis'
278325
strategy:

CMakeLists.txt

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# This CMake build file is intended for use with the llvm-mingw toolchain:
2+
# https://github.com/mstorsjo/llvm-mingw
3+
#
4+
# It most probably doesn't work with MSVC.
5+
6+
cmake_minimum_required(VERSION 3.12)
7+
8+
project(cppwinrt LANGUAGES CXX)
9+
10+
set(CMAKE_CXX_STANDARD 17)
11+
set(CMAKE_CXX_STANDARD_REQUIRED True)
12+
13+
set(CPPWINRT_BUILD_VERSION "2.3.4.5" CACHE STRING "The version string used for cppwinrt.")
14+
add_compile_definitions(CPPWINRT_VERSION_STRING="${CPPWINRT_BUILD_VERSION}")
15+
16+
# WinMD uses CreateFile2 which requires Windows 8.
17+
add_compile_definitions(_WIN32_WINNT=0x0602)
18+
19+
20+
# === prebuild: Generator tool for strings.cpp, strings.h, version.rc ===
21+
22+
set(PREBUILD_SRCS
23+
prebuild/main.cpp
24+
prebuild/pch.h
25+
)
26+
add_executable(prebuild ${PREBUILD_SRCS})
27+
target_include_directories(prebuild PRIVATE cppwinrt/)
28+
29+
30+
# === Step to create autogenerated files ===
31+
32+
file(GLOB PREBUILD_STRINGS_FILES
33+
LIST_DIRECTORIES false
34+
CONFIGURE_DEPENDS
35+
strings/*.h
36+
)
37+
add_custom_command(
38+
OUTPUT
39+
${PROJECT_BINARY_DIR}/strings.cpp
40+
${PROJECT_BINARY_DIR}/version.rc
41+
COMMAND "${PROJECT_BINARY_DIR}/prebuild.exe" ARGS "${PROJECT_SOURCE_DIR}/strings" "${PROJECT_BINARY_DIR}"
42+
DEPENDS
43+
prebuild
44+
${PREBUILD_STRINGS_FILES}
45+
VERBATIM
46+
)
47+
48+
49+
# === cppwinrt ===
50+
51+
set(CPPWINRT_SRCS
52+
cppwinrt/main.cpp
53+
"${PROJECT_BINARY_DIR}/strings.cpp"
54+
)
55+
56+
set(CPPWINRT_HEADERS
57+
cppwinrt/pch.h
58+
cppwinrt/cmd_reader.h
59+
cppwinrt/code_writers.h
60+
cppwinrt/component_writers.h
61+
cppwinrt/file_writers.h
62+
cppwinrt/helpers.h
63+
cppwinrt/pch.h
64+
cppwinrt/settings.h
65+
cppwinrt/task_group.h
66+
cppwinrt/text_writer.h
67+
cppwinrt/type_writers.h
68+
)
69+
70+
add_custom_command(
71+
OUTPUT
72+
"${PROJECT_BINARY_DIR}/app.manifest"
73+
COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/cppwinrt/app.manifest" "${PROJECT_BINARY_DIR}/app.manifest"
74+
DEPENDS "${PROJECT_SOURCE_DIR}/cppwinrt/app.manifest"
75+
VERBATIM
76+
)
77+
# Do the configure_file dance so that app.manifest.rc don't get modified every
78+
# single time the project is reconfigured and trigger a rebuild.
79+
file(WRITE "${PROJECT_BINARY_DIR}/app.manifest.rc.in" "1 24 \"app.manifest\"\n")
80+
configure_file(
81+
"${PROJECT_BINARY_DIR}/app.manifest.rc.in"
82+
"${PROJECT_BINARY_DIR}/app.manifest.rc"
83+
COPYONLY
84+
)
85+
86+
set(CPPWINRT_RESOURCES
87+
"${PROJECT_BINARY_DIR}/app.manifest"
88+
"${PROJECT_BINARY_DIR}/app.manifest.rc"
89+
"${PROJECT_BINARY_DIR}/version.rc"
90+
)
91+
92+
add_executable(cppwinrt ${CPPWINRT_SRCS} ${CPPWINRT_RESOURCES} ${CPPWINRT_HEADERS})
93+
target_include_directories(cppwinrt PRIVATE ${PROJECT_BINARY_DIR})
94+
target_link_libraries(cppwinrt shlwapi)
95+
96+
97+
# HACK: Handle the xmllite import lib.
98+
# mingw-w64 before commit 5ac1a2c is missing the import lib for xmllite. This
99+
# checks whether the current build environment provides libxmllite.a, and
100+
# generates the import lib if needed.
101+
102+
set(XMLLITE_LIBRARY xmllite)
103+
if(MINGW)
104+
function(TestLinkXmlLite OUTPUT_VARNAME)
105+
include(CheckCXXSourceCompiles)
106+
set(CMAKE_REQUIRED_LIBRARIES xmllite)
107+
check_cxx_source_compiles("
108+
#include <xmllite.h>
109+
int main() {
110+
CreateXmlReader(__uuidof(IXmlReader), nullptr, nullptr);
111+
}
112+
" ${OUTPUT_VARNAME})
113+
endfunction()
114+
115+
function(TestIsI386 OUTPUT_VARNAME)
116+
include(CheckCXXSourceCompiles)
117+
check_cxx_source_compiles("
118+
#if !defined(__i386__) && !defined(_M_IX86)
119+
# error Not i386
120+
#endif
121+
int main() {}
122+
" ${OUTPUT_VARNAME})
123+
endfunction()
124+
125+
TestLinkXmlLite(HAS_LIBXMLLITE)
126+
if(NOT HAS_LIBXMLLITE)
127+
TestIsI386(TARGET_IS_I386)
128+
if(TARGET_IS_I386)
129+
set(XMLLITE_DEF_FILE xmllite_i386)
130+
else()
131+
set(XMLLITE_DEF_FILE xmllite)
132+
endif()
133+
add_custom_command(
134+
OUTPUT
135+
"${PROJECT_BINARY_DIR}/libxmllite.a"
136+
COMMAND dlltool -k -d "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def" -l "${PROJECT_BINARY_DIR}/libxmllite.a"
137+
DEPENDS "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def"
138+
VERBATIM
139+
)
140+
add_custom_target(gen-libxmllite
141+
DEPENDS "${PROJECT_BINARY_DIR}/libxmllite.a"
142+
)
143+
set(XMLLITE_LIBRARY "${PROJECT_BINARY_DIR}/libxmllite.a")
144+
add_dependencies(cppwinrt gen-libxmllite)
145+
endif()
146+
endif()
147+
target_link_libraries(cppwinrt "${XMLLITE_LIBRARY}")
148+
149+
150+
# === winmd: External header-only library for reading winmd files ===
151+
152+
include(ExternalProject)
153+
ExternalProject_Add(winmd
154+
URL https://github.com/microsoft/winmd/releases/download/1.0.210629.2/Microsoft.Windows.WinMD.1.0.210629.2.nupkg
155+
URL_HASH SHA256=4c5f29d948f5b3d724d229664c8f8e4823250d3c9f23ad8067b732fc7076d8c7
156+
CONFIGURE_COMMAND ""
157+
BUILD_COMMAND ""
158+
INSTALL_COMMAND ""
159+
)
160+
add_dependencies(cppwinrt winmd)
161+
ExternalProject_Get_Property(winmd SOURCE_DIR)
162+
set(winmd_SOURCE_DIR "${SOURCE_DIR}")
163+
target_include_directories(cppwinrt PRIVATE "${winmd_SOURCE_DIR}")
164+
165+
166+
include(CTest)
167+
add_subdirectory(test)

mingw-support/xmllite.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
LIBRARY "XmlLite.dll"
2+
EXPORTS
3+
CreateXmlReader
4+
CreateXmlReaderInputWithEncodingCodePage
5+
CreateXmlReaderInputWithEncodingName
6+
CreateXmlWriter
7+
CreateXmlWriterOutputWithEncodingCodePage
8+
CreateXmlWriterOutputWithEncodingName

mingw-support/xmllite_i386.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
LIBRARY "XmlLite.dll"
2+
EXPORTS
3+
CreateXmlReader@12
4+
CreateXmlReaderInputWithEncodingCodePage@24
5+
CreateXmlReaderInputWithEncodingName@24
6+
CreateXmlWriter@12
7+
CreateXmlWriterOutputWithEncodingCodePage@16
8+
CreateXmlWriterOutputWithEncodingName@16

test/CMakeLists.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# The tests use newer C++ features.
2+
set(CMAKE_CXX_STANDARD 20)
3+
4+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
5+
6+
include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
7+
include_directories("${PROJECT_SOURCE_DIR}/cppwinrt")
8+
include_directories("${CMAKE_CURRENT_BINARY_DIR}/cppwinrt")
9+
10+
function(TestIsX64 OUTPUT_VARNAME)
11+
include(CheckCXXSourceCompiles)
12+
check_cxx_source_compiles("
13+
#if !defined(__x86_64__) && !defined(_M_X64)
14+
# error Not x86_64
15+
#endif
16+
int main() {}
17+
" ${OUTPUT_VARNAME})
18+
endfunction()
19+
TestIsX64(TARGET_IS_X64)
20+
if(TARGET_IS_X64)
21+
add_compile_options(-mcx16)
22+
endif()
23+
24+
25+
add_custom_command(
26+
OUTPUT
27+
"${CMAKE_CURRENT_BINARY_DIR}/cppwinrt/winrt/base.h"
28+
COMMAND "${PROJECT_BINARY_DIR}/cppwinrt" -input local -output "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt" -verbose
29+
DEPENDS
30+
cppwinrt
31+
VERBATIM
32+
)
33+
add_custom_target(build-cppwinrt-projection
34+
DEPENDS
35+
"${CMAKE_CURRENT_BINARY_DIR}/cppwinrt/winrt/base.h"
36+
)
37+
38+
39+
add_subdirectory(test)
40+
add_subdirectory(test_win7)

test/mingw_com_support.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#if defined(__clang__)
2+
#define HAS_DECLSPEC_UUID __has_declspec_attribute(uuid)
3+
#elif defined(_MSC_VER)
4+
#define HAS_DECLSPEC_UUID 1
5+
#else
6+
#define HAS_DECLSPEC_UUID 0
7+
#endif
8+
9+
#if HAS_DECLSPEC_UUID
10+
#define DECLSPEC_UUID(x) __declspec(uuid(x))
11+
#else
12+
#define DECLSPEC_UUID(x)
13+
#endif

test/test/CMakeLists.txt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
file(GLOB TEST_SRCS
2+
LIST_DIRECTORIES false
3+
CONFIGURE_DEPENDS
4+
*.cpp
5+
)
6+
list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp")
7+
8+
9+
# We can't build test_component[*] for mingw-w64 because it doesn't have an
10+
# alternative to midl that can produce winmd files. Also, even if we do manage
11+
# to reuse the MSVC-compiled binaries, mingw-w64 is still missing
12+
# windowsnumerics.impl.h which is needed to provide the types
13+
# winrt::Windows::Foundation::Numerics::float2 and friends that the components
14+
# use.
15+
list(APPEND BROKEN_TESTS
16+
agility
17+
delegates
18+
enum
19+
event_deferral
20+
in_params
21+
in_params_abi
22+
no_make_detection
23+
noexcept
24+
optional
25+
out_params
26+
out_params_abi
27+
parent_includes
28+
rational
29+
return_params
30+
return_params_abi
31+
struct_delegate
32+
structs
33+
uniform_in_params
34+
velocity
35+
)
36+
37+
list(APPEND BROKEN_TESTS
38+
# depends on pplawait.h
39+
when
40+
)
41+
42+
# Exclude broken tests
43+
foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS)
44+
list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp")
45+
endforeach()
46+
47+
add_executable(test-vanilla main.cpp ${TEST_SRCS})
48+
set_target_properties(test-vanilla PROPERTIES OUTPUT_NAME "test")
49+
target_link_libraries(test-vanilla runtimeobject)
50+
51+
target_precompile_headers(test-vanilla PRIVATE pch.h)
52+
set_source_files_properties(
53+
main.cpp
54+
coro_foundation.cpp
55+
coro_system.cpp
56+
coro_threadpool.cpp
57+
coro_uicore.cpp
58+
custom_activation.cpp
59+
generic_type_names.cpp
60+
guid_include.cpp
61+
inspectable_interop.cpp
62+
module_lock_dll.cpp
63+
PROPERTIES SKIP_PRECOMPILE_HEADERS true
64+
)
65+
66+
add_dependencies(test-vanilla build-cppwinrt-projection)
67+
68+
add_test(
69+
NAME test
70+
COMMAND "$<TARGET_FILE:test-vanilla>"
71+
)

test/test/async_auto_cancel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ namespace
8383
}
8484
}
8585

86-
#if defined(__clang__)
86+
#if defined(__clang__) && defined(_MSC_VER)
8787
// FIXME: Test is known to segfault when built with Clang.
8888
TEST_CASE("async_auto_cancel", "[.clang-crash]")
8989
#else

test/test/async_cancel_callback.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ namespace
9393
}
9494
}
9595

96-
#if defined(__clang__)
96+
#if defined(__clang__) && defined(_MSC_VER)
9797
// FIXME: Test is known to segfault when built with Clang.
9898
TEST_CASE("async_cancel_callback", "[.clang-crash]")
9999
#else

test/test/async_check_cancel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ namespace
104104
}
105105
}
106106

107-
#if defined(__clang__)
107+
#if defined(__clang__) && defined(_MSC_VER)
108108
// FIXME: Test is known to segfault when built with Clang.
109109
TEST_CASE("async_check_cancel", "[.clang-crash]")
110110
#else

0 commit comments

Comments
 (0)