Skip to content

Commit 2c04af8

Browse files
authored
Wrap compiler when FIPS w/ clang v20+ (#2671)
1 parent 78ada21 commit 2c04af8

File tree

5 files changed

+325
-13
lines changed

5 files changed

+325
-13
lines changed

.github/workflows/actions-ci.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,6 @@ jobs:
222222
- 'clang19'
223223
- 'clang20'
224224
- 'clang21'
225-
exclude:
226-
- fips: 1
227-
compiler: 'clang20'
228-
- fips: 1
229-
compiler: 'clang21'
230225
runs-on: ubuntu-latest
231226
container:
232227
image: ghcr.io/mattkretz/cplusplus-ci/${{ matrix.compiler }}
@@ -305,11 +300,6 @@ jobs:
305300
- 'gcc15'
306301
- 'clang19'
307302
- 'clang20'
308-
exclude:
309-
- fips: 1
310-
compiler: 'gcc15'
311-
- fips: 1
312-
compiler: 'clang20'
313303
runs-on: ubuntu-latest
314304
container:
315305
image: ghcr.io/mattkretz/cplusplus-ci/${{ matrix.compiler }}

crypto/fipsmodule/CMakeLists.txt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,9 +422,11 @@ if(FIPS_DELOCATE)
422422
set_target_properties(bcm_c_generated_asm PROPERTIES COMPILE_OPTIONS "-S")
423423
set_target_properties(bcm_c_generated_asm PROPERTIES POSITION_INDEPENDENT_CODE ON)
424424

425-
# Clang 20+ warns when both "-S" and "-c" are used as options to the compiler.
426-
if (CLANG AND (CMAKE_ASM_COMPILER_ID MATCHES "Clang" OR CMAKE_ASM_COMPILER MATCHES "clang") AND (CMAKE_C_COMPILER_VERSION VERSION_GREATER "19.99.99"))
427-
set_target_properties(bcm_c_generated_asm PROPERTIES COMPILE_OPTIONS "-Wno-unused-command-line-argument")
425+
get_filename_component(COMPILER_WRAPPER_PATH ${AWSLC_SOURCE_DIR}/util/compiler_wrapper/CompilerWrapper.cmake REALPATH)
426+
include(${COMPILER_WRAPPER_PATH})
427+
setup_compiler_wrapper()
428+
if(COMPILER_WRAPPER_AVAILABLE)
429+
use_compiler_wrapper_for_target(bcm_c_generated_asm)
428430
endif()
429431

430432
set(TARGET "")
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0 OR ISC
3+
4+
# CompilerWrapper.cmake
5+
#
6+
# CMake module for handling compiler flag conflicts, particularly the -S/-c conflict
7+
# in newer Clang versions when generating assembly output.
8+
#
9+
# This module dynamically generates wrapper scripts with hardcoded compiler paths,
10+
# eliminating the need for complex compiler discovery logic.
11+
#
12+
# Usage:
13+
# include(CompilerWrapper)
14+
# setup_compiler_wrapper()
15+
# use_compiler_wrapper_for_target(my_target)
16+
17+
cmake_minimum_required(VERSION 3.5)
18+
19+
# Check if we need the compiler wrapper based on compiler version
20+
function(compiler_wrapper_needed result_var)
21+
set(${result_var} FALSE PARENT_SCOPE)
22+
23+
# Check C compiler
24+
if(CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER MATCHES "clang")
25+
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER "19.99.99")
26+
set(${result_var} TRUE PARENT_SCOPE)
27+
return()
28+
endif()
29+
endif()
30+
31+
# Allow manual override via CMake variable
32+
if(FORCE_COMPILER_WRAPPER)
33+
set(${result_var} TRUE PARENT_SCOPE)
34+
endif()
35+
endfunction()
36+
37+
# Generate wrapper scripts with hardcoded compiler paths
38+
function(generate_compiler_wrapper)
39+
# Get current timestamp for generated file header
40+
string(TIMESTAMP CURRENT_TIMESTAMP UTC)
41+
42+
# Set output directory for generated wrappers
43+
set(WRAPPER_OUTPUT_DIR "${CMAKE_BINARY_DIR}/compiler_wrapper")
44+
file(MAKE_DIRECTORY "${WRAPPER_OUTPUT_DIR}")
45+
46+
# Generate shell script wrapper (Unix/Linux/macOS)
47+
set(SHELL_TEMPLATE "${CMAKE_SOURCE_DIR}/util/compiler_wrapper/compiler_wrapper_template.sh.in")
48+
set(SHELL_OUTPUT "${WRAPPER_OUTPUT_DIR}/compiler_wrapper.sh")
49+
50+
if(EXISTS "${SHELL_TEMPLATE}")
51+
# Output file retains permissions of source file.
52+
configure_file(
53+
"${SHELL_TEMPLATE}"
54+
"${SHELL_OUTPUT}"
55+
@ONLY
56+
)
57+
58+
set(COMPILER_WRAPPER_SHELL "${SHELL_OUTPUT}" PARENT_SCOPE)
59+
message(STATUS "Generated shell wrapper: ${SHELL_OUTPUT}")
60+
else()
61+
message(WARNING "Shell wrapper template not found: ${SHELL_TEMPLATE}")
62+
endif()
63+
64+
# Generate batch file wrapper (Windows)
65+
set(BAT_TEMPLATE "${CMAKE_SOURCE_DIR}/util/compiler_wrapper/compiler_wrapper_template.bat.in")
66+
set(BAT_OUTPUT "${WRAPPER_OUTPUT_DIR}/compiler_wrapper.bat")
67+
68+
if(EXISTS "${BAT_TEMPLATE}")
69+
configure_file(
70+
"${BAT_TEMPLATE}"
71+
"${BAT_OUTPUT}"
72+
@ONLY
73+
)
74+
75+
set(COMPILER_WRAPPER_BAT "${BAT_OUTPUT}" PARENT_SCOPE)
76+
message(STATUS "Generated batch wrapper: ${BAT_OUTPUT}")
77+
else()
78+
message(WARNING "Batch wrapper template not found: ${BAT_TEMPLATE}")
79+
endif()
80+
endfunction()
81+
82+
# Get the appropriate wrapper script for the current platform
83+
function(get_platform_wrapper result_var)
84+
if(WIN32 AND COMPILER_WRAPPER_BAT
85+
AND EXISTS "${COMPILER_WRAPPER_BAT}")
86+
set(${result_var} "${COMPILER_WRAPPER_BAT}" PARENT_SCOPE)
87+
elseif(COMPILER_WRAPPER_SHELL AND EXISTS "${COMPILER_WRAPPER_SHELL}")
88+
set(${result_var} "${COMPILER_WRAPPER_SHELL}" PARENT_SCOPE)
89+
else()
90+
set(${result_var} "" PARENT_SCOPE)
91+
endif()
92+
endfunction()
93+
94+
# Set up the compiler wrapper system
95+
function(setup_compiler_wrapper)
96+
# Check if we need the wrapper
97+
compiler_wrapper_needed(NEED_WRAPPER)
98+
if(NOT NEED_WRAPPER)
99+
message(STATUS "Compiler wrapper not needed for current compiler version")
100+
set(COMPILER_WRAPPER_AVAILABLE FALSE CACHE INTERNAL "Whether compiler wrapper is available")
101+
return()
102+
endif()
103+
104+
# Determine the compiler to wrap
105+
set(REAL_COMPILER "${CMAKE_C_COMPILER}")
106+
if(NOT REAL_COMPILER)
107+
message(FATAL_ERROR "CMAKE_C_COMPILER is not set, cannot generate compiler wrapper")
108+
endif()
109+
110+
# Convert to absolute path if needed
111+
if(NOT IS_ABSOLUTE "${REAL_COMPILER}")
112+
find_program(REAL_COMPILER_ABS "${REAL_COMPILER}")
113+
if(REAL_COMPILER_ABS)
114+
set(REAL_COMPILER "${REAL_COMPILER_ABS}")
115+
else()
116+
message(WARNING "Could not find absolute path for compiler: ${REAL_COMPILER}")
117+
endif()
118+
endif()
119+
120+
# Verify compiler exists
121+
if(NOT EXISTS "${REAL_COMPILER}")
122+
message(FATAL_ERROR "Compiler not found: ${REAL_COMPILER}")
123+
endif()
124+
125+
message(STATUS "Generating compiler wrapper for: ${REAL_COMPILER}")
126+
127+
# Generate the wrapper scripts
128+
generate_compiler_wrapper()
129+
# Get the platform-appropriate wrapper
130+
get_platform_wrapper(WRAPPER_SCRIPT)
131+
132+
if(NOT WRAPPER_SCRIPT OR NOT EXISTS "${WRAPPER_SCRIPT}")
133+
message(FATAL_ERROR "Failed to generate compiler wrapper script")
134+
endif()
135+
136+
# Store wrapper information in cache for use by other functions
137+
set(COMPILER_WRAPPER_SCRIPT "${WRAPPER_SCRIPT}" CACHE INTERNAL "Path to generated compiler wrapper script")
138+
set(COMPILER_WRAPPER_REAL_COMPILER "${REAL_COMPILER}" CACHE INTERNAL "Real compiler being wrapped")
139+
set(COMPILER_WRAPPER_AVAILABLE TRUE CACHE INTERNAL "Whether compiler wrapper is available")
140+
141+
message(STATUS "Compiler wrapper ready: ${WRAPPER_SCRIPT}")
142+
endfunction()
143+
144+
# Apply the compiler wrapper to a specific target
145+
function(use_compiler_wrapper_for_target target_name)
146+
# Check that wrapper is available
147+
if(NOT COMPILER_WRAPPER_AVAILABLE)
148+
message(STATUS "Compiler wrapper not available for target ${target_name}")
149+
return()
150+
endif()
151+
152+
# Check that target exists
153+
if(NOT TARGET ${target_name})
154+
message(WARNING "Target ${target_name} does not exist, cannot apply compiler wrapper")
155+
return()
156+
endif()
157+
158+
# Set the compiler launcher to use our wrapper
159+
set_target_properties(${target_name} PROPERTIES
160+
C_COMPILER_LAUNCHER "${COMPILER_WRAPPER_SCRIPT}"
161+
)
162+
163+
message(STATUS "Applied compiler wrapper to target: ${target_name}")
164+
endfunction()
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
@echo off
2+
:: Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
:: SPDX-License-Identifier: Apache-2.0 OR ISC
4+
5+
:: Dynamically generated compiler wrapper script
6+
:: This file is generated by CMake from compiler_wrapper_template.bat.in
7+
::
8+
:: Real compiler: @REAL_COMPILER@
9+
:: Generated on: @CURRENT_TIMESTAMP@
10+
::
11+
:: Purpose: Filter out conflicting -c flags when -S flag is present
12+
:: to avoid issues with newer Clang versions (20+)
13+
14+
setlocal enabledelayedexpansion
15+
16+
:: The real compiler path (filled in by CMake)
17+
set "REAL_COMPILER=@REAL_COMPILER@"
18+
19+
:: Verify the compiler exists
20+
if not exist "!REAL_COMPILER!" (
21+
echo Error: Compiler not found: !REAL_COMPILER! >&2
22+
exit /b 1
23+
)
24+
25+
:: Check if we have any arguments
26+
if "%~1"=="" (
27+
echo Error: No arguments provided to compiler wrapper >&2
28+
echo Usage: %~n0 ^<compiler_args^> >&2
29+
exit /b 1
30+
)
31+
32+
:: Initialize variables
33+
set "has_s_flag=false"
34+
set "has_c_flag=false"
35+
set "filtered_args="
36+
37+
:: First pass: check for conflicting flags
38+
for %%i in (%*) do (
39+
if "%%i"=="-S" set "has_s_flag=true"
40+
if "%%i"=="-c" set "has_c_flag=true"
41+
)
42+
43+
:: Second pass: build filtered arguments
44+
for %%i in (%*) do (
45+
set "include_arg=true"
46+
47+
:: If we have -S flag and current arg is -c, exclude it
48+
if "!has_s_flag!"=="true" (
49+
if "%%i"=="-c" set "include_arg=false"
50+
)
51+
52+
:: Add argument to filtered list if we should include it
53+
if "!include_arg!"=="true" (
54+
if "!filtered_args!"=="" (
55+
set "filtered_args=%%i"
56+
) else (
57+
set "filtered_args=!filtered_args! %%i"
58+
)
59+
)
60+
)
61+
62+
:: Debug output if requested
63+
if not "%COMPILER_WRAPPER_DEBUG%"=="" (
64+
echo WRAPPER DEBUG: Real compiler: !REAL_COMPILER! >&2
65+
if "!has_s_flag!"=="true" (
66+
if "!has_c_flag!"=="true" (
67+
echo WRAPPER DEBUG: Filtered out conflicting -c flag ^(keeping -S^) >&2
68+
)
69+
)
70+
echo WRAPPER DEBUG: Executing: !REAL_COMPILER! !filtered_args! >&2
71+
)
72+
73+
:: Execute the real compiler
74+
"!REAL_COMPILER!" !filtered_args!
75+
exit /b %errorlevel%
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env sh
2+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
# SPDX-License-Identifier: Apache-2.0 OR ISC
4+
5+
# Dynamically generated compiler wrapper script
6+
# This file is generated by CMake from compiler_wrapper_template.sh.in
7+
#
8+
# Real compiler: @REAL_COMPILER@
9+
# Generated on: @CURRENT_TIMESTAMP@
10+
#
11+
# Purpose: Filter out conflicting -c flags when -S flag is present
12+
# to avoid issues with newer Clang versions (20+)
13+
14+
set -e
15+
16+
# The real compiler path (filled in by CMake)
17+
REAL_COMPILER="@REAL_COMPILER@"
18+
19+
# Verify the compiler exists
20+
if [ ! -x "$REAL_COMPILER" ]; then
21+
echo "Error: Compiler not found or not executable: $REAL_COMPILER" >&2
22+
exit 1
23+
fi
24+
25+
# When used as COMPILER_LAUNCHER, the real compiler path is passed as first argument
26+
# Skip it if it matches our configured REAL_COMPILER
27+
if [ $# -gt 0 ] && [ "$1" = "$REAL_COMPILER" ]; then
28+
shift
29+
fi
30+
31+
# Check if we have both -S and -c flags
32+
has_s_flag=false
33+
has_c_flag=false
34+
for arg in "$@"; do
35+
case "$arg" in
36+
-S) has_s_flag=true ;;
37+
-c) has_c_flag=true ;;
38+
esac
39+
done
40+
41+
# If we have both flags, filter out -c and rebuild argument list
42+
filtered=false
43+
if [ "$has_s_flag" = true ] && [ "$has_c_flag" = true ]; then
44+
# Build new argument list by iterating through original args
45+
new_args=""
46+
arg_count=0
47+
48+
for arg in "$@"; do
49+
case "$arg" in
50+
-c)
51+
# Skip -c flag
52+
filtered=true
53+
;;
54+
*)
55+
# Keep this argument - use positional parameter trick
56+
arg_count=$((arg_count + 1))
57+
eval "arg_$arg_count=\"\$arg\""
58+
;;
59+
esac
60+
done
61+
62+
# Rebuild $@ with filtered arguments
63+
set --
64+
i=1
65+
while [ $i -le $arg_count ]; do
66+
eval "set -- \"\$@\" \"\$arg_$i\""
67+
i=$((i + 1))
68+
done
69+
fi
70+
71+
# Debug output
72+
if [ -n "$COMPILER_WRAPPER_DEBUG" ]; then
73+
echo "WRAPPER DEBUG: Real compiler: $REAL_COMPILER" >&2
74+
if [ "$filtered" = true ]; then
75+
echo "WRAPPER DEBUG: Filtered out conflicting -c flag (keeping -S)" >&2
76+
fi
77+
echo "WRAPPER DEBUG: Executing: $REAL_COMPILER $*" >&2
78+
fi
79+
80+
# Execute the real compiler
81+
exec "$REAL_COMPILER" "$@"

0 commit comments

Comments
 (0)