Skip to content

Commit db74d22

Browse files
fix: SG-42386: Replace linux commands with CMake (#1195)
### Linked issues Fixes SG-42386 ### Summarize your change. Replace all Unix command-line tool dependencies (`sed`, `bash`, `grep`, `cut`, `wc`, `cat`) in the CMake build system with pure CMake implementations using a unified CMake script-mode file (`apply_sed_filter.cmake`) and native CMake string operations. ### Describe the reason for the change. The build system relied on Unix tools (`sed`, `bash -c`, `grep`, `cut`, `wc`) for text processing, which are not natively available on Windows. This prevented the build from working on Windows without additional tool installation (e.g., MSYS2/Git Bash). ### Describe what you have tested and on which operating system. I looked at the files before and after, and the files looks ok as far as I can tell. ### Add a list of changes, and note any that might need special attention during the review. ### If possible, provide screenshots. --------- Signed-off-by: Cédrik Fuoco <cedrik.fuoco@autodesk.com>
1 parent 3e5c402 commit db74d22

7 files changed

Lines changed: 193 additions & 28 deletions

File tree

cmake/macros/rv_lex.cmake

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,46 @@
55
#
66

77
INCLUDE(rv_sed)
8-
FIND_PROGRAM(_lex flex NO_CACHE REQUIRED)
98

10-
EXECUTE_PROCESS(
11-
COMMAND bash "-c" "${_lex} --version | cut -d '.' -f 2"
12-
OUTPUT_VARIABLE _flex_minor_version
13-
OUTPUT_STRIP_TRAILING_WHITESPACE
14-
)
9+
# Find the lexer tool: prefer win_flex on Windows, fall back to flex
10+
IF(RV_TARGET_WINDOWS)
11+
FIND_PROGRAM(_lex win_flex NO_CACHE)
12+
IF(NOT _lex)
13+
FIND_PROGRAM(_lex flex NO_CACHE REQUIRED)
14+
ENDIF()
15+
ELSE()
16+
FIND_PROGRAM(_lex flex NO_CACHE REQUIRED)
17+
ENDIF()
1518

19+
# Get flex version using CMake string operations (no bash needed)
1620
EXECUTE_PROCESS(
17-
COMMAND bash "-c" "${_lex} --version | grep Apple | wc -l | ${_sed} 's/ //g'"
18-
OUTPUT_VARIABLE _flex_apple
21+
COMMAND ${_lex} --version
22+
OUTPUT_VARIABLE _flex_version_output
1923
OUTPUT_STRIP_TRAILING_WHITESPACE
2024
)
25+
# Extract minor version: output is like "flex 2.6.4" or "win_flex 2.6.4"
26+
STRING(REGEX MATCH "[0-9]+\\.([0-9]+)" _flex_version_match "${_flex_version_output}")
27+
SET(_flex_minor_version
28+
"${CMAKE_MATCH_1}"
29+
)
30+
31+
# Detect Apple flex (only relevant on macOS)
32+
IF(APPLE)
33+
STRING(FIND "${_flex_version_output}" "Apple" _apple_pos)
34+
IF(_apple_pos GREATER -1)
35+
SET(_flex_apple
36+
1
37+
)
38+
ELSE()
39+
SET(_flex_apple
40+
0
41+
)
42+
ENDIF()
43+
ELSE()
44+
SET(_flex_apple
45+
0
46+
)
47+
ENDIF()
2148

2249
SET(RV_FLEX_MINOR_VERSION
2350
${_flex_minor_version}

cmake/macros/rv_sed.cmake

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
# SPDX-License-Identifier: Apache-2.0
55
#
66

7-
FIND_PROGRAM(_sed sed NO_CACHE REQUIRED)
7+
SET(_apply_sed_script
8+
"${PROJECT_SOURCE_DIR}/cmake/scripts/apply_sed_filter.cmake"
9+
)
810

911
#
1012
# 01234567890123456789012345678901234567890123456789012345678901234567890123456789 ! sed_it2 : wraps a call to the 'sed' utility.
@@ -85,12 +87,10 @@ FUNCTION(sed_it)
8587
MESSAGE(DEBUG "_temp: '${_temp}'")
8688

8789
#
88-
# Actual SED operation
90+
# Actual SED operation via CMake script mode
8991
EXECUTE_PROCESS(
9092
WORKING_DIRECTORY ${arg_OUTPUT_DIR}
91-
COMMAND ${_sed} -f ${arg_INPUT_SED_FILE} ${arg_INPUT_FILE} COMMAND_ECHO STDOUT
92-
OUTPUT_FILE ${_temp}
93-
OUTPUT_STRIP_TRAILING_WHITESPACE
93+
COMMAND ${CMAKE_COMMAND} -DINPUT_FILE=${arg_INPUT_FILE} -DOUTPUT_FILE=${_temp} -DSED_FILE=${arg_INPUT_SED_FILE} -P ${_apply_sed_script} COMMAND_ECHO STDOUT
9494
RESULT_VARIABLE _result_code COMMAND_ERROR_IS_FATAL ANY
9595
)
9696

cmake/macros/rv_stage.cmake

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -416,16 +416,12 @@ FUNCTION(rv_stage)
416416

417417
SET_DIRECTORY_PROPERTIES(PROPERTIES CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_package_file})
418418

419-
EXECUTE_PROCESS(
420-
COMMAND bash -c "cat ${_package_file} | grep version: | grep --only-matching -e '[0-9.]*'"
421-
RESULT_VARIABLE _result
422-
OUTPUT_VARIABLE _pkg_version
423-
OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ERROR_IS_FATAL ANY
424-
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
425-
)
426-
IF(_result
427-
AND NOT _result EQUAL 0
419+
FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/${_package_file}" _package_file_content)
420+
STRING(REGEX MATCH "version:[ \t]*([0-9.]+)" _version_match "${_package_file_content}")
421+
SET(_pkg_version
422+
"${CMAKE_MATCH_1}"
428423
)
424+
IF(NOT _pkg_version)
429425
MESSAGE(FATAL_ERROR "Error retrieving version field from '${_package_file}'")
430426
ELSE()
431427
MESSAGE(DEBUG "Found version for '${arg_TARGET}.rvpkg' package version ${_pkg_version} ...")

cmake/macros/rv_yacc.cmake

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,15 @@
66

77
FUNCTION(yacc_it)
88

9-
FIND_PROGRAM(_yacc bison NO_CACHE REQUIRED)
10-
FIND_PROGRAM(_sed sed NO_CACHE REQUIRED)
9+
# Find the parser generator: prefer win_bison on Windows, fall back to bison
10+
IF(RV_TARGET_WINDOWS)
11+
FIND_PROGRAM(_yacc win_bison NO_CACHE)
12+
IF(NOT _yacc)
13+
FIND_PROGRAM(_yacc bison NO_CACHE REQUIRED)
14+
ENDIF()
15+
ELSE()
16+
FIND_PROGRAM(_yacc bison NO_CACHE REQUIRED)
17+
ENDIF()
1118

1219
SET(flags)
1320
SET(args)
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#
2+
# Copyright (C) 2026 Autodesk, Inc. All Rights Reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
#
8+
# CMake script-mode file for applying sed-style substitutions. Replaces bash+sed and Python-based approaches with pure CMake.
9+
#
10+
# Usage: cmake -DINPUT_FILE=<path> -DOUTPUT_FILE=<path> -DSED_FILE=<path> -P apply_sed_filter.cmake
11+
#
12+
# Supports: - Literal s/PATTERN/REPLACEMENT/ substitutions - PCRE negative lookbehind patterns (?<!PREFIX)MATCH via three-pass workaround - Any single-character
13+
# delimiter after 's'
14+
#
15+
16+
IF(NOT INPUT_FILE)
17+
MESSAGE(FATAL_ERROR "INPUT_FILE not specified")
18+
ENDIF()
19+
IF(NOT OUTPUT_FILE)
20+
MESSAGE(FATAL_ERROR "OUTPUT_FILE not specified")
21+
ENDIF()
22+
IF(NOT SED_FILE)
23+
MESSAGE(FATAL_ERROR "SED_FILE not specified")
24+
ENDIF()
25+
26+
FILE(READ "${INPUT_FILE}" _content)
27+
FILE(READ "${SED_FILE}" _sed_content)
28+
29+
# Protect semicolons before splitting into CMake list (CMake uses ; as list separator)
30+
STRING(REPLACE ";" "@@SEMICOLON@@" _sed_content "${_sed_content}")
31+
STRING(REPLACE "\n" ";" _sed_lines "${_sed_content}")
32+
33+
SET(_placeholder_counter
34+
0
35+
)
36+
37+
FOREACH(
38+
_line IN
39+
LISTS _sed_lines
40+
)
41+
# Restore semicolons within each line
42+
STRING(REPLACE "@@SEMICOLON@@" ";" _line "${_line}")
43+
STRING(STRIP "${_line}" _line)
44+
45+
IF("${_line}" STREQUAL ""
46+
OR "${_line}" MATCHES "^#"
47+
)
48+
CONTINUE()
49+
ENDIF()
50+
51+
# Must start with 's'
52+
STRING(SUBSTRING "${_line}" 0 1 _prefix)
53+
IF(NOT "${_prefix}" STREQUAL "s")
54+
CONTINUE()
55+
ENDIF()
56+
57+
# Detect delimiter (char after 's')
58+
STRING(SUBSTRING "${_line}" 1 1 _delim)
59+
STRING(SUBSTRING "${_line}" 2 -1 _rest)
60+
61+
# Find delimiter separating pattern from replacement
62+
STRING(FIND "${_rest}" "${_delim}" _split_pos)
63+
IF(_split_pos EQUAL -1)
64+
CONTINUE()
65+
ENDIF()
66+
STRING(SUBSTRING "${_rest}" 0 ${_split_pos} _pattern)
67+
MATH(EXPR _repl_start "${_split_pos} + 1")
68+
STRING(SUBSTRING "${_rest}" ${_repl_start} -1 _repl_rest)
69+
70+
# Find trailing delimiter
71+
STRING(FIND "${_repl_rest}" "${_delim}" _end_pos)
72+
IF(_end_pos GREATER -1)
73+
STRING(SUBSTRING "${_repl_rest}" 0 ${_end_pos} _replacement)
74+
ELSE()
75+
SET(_replacement
76+
"${_repl_rest}"
77+
)
78+
ENDIF()
79+
80+
# Check for PCRE negative lookbehind: (?<!PREFIX)MATCH
81+
STRING(FIND "${_pattern}" "(?<!" _lb_pos)
82+
IF(NOT _lb_pos EQUAL -1)
83+
# Extract the lookbehind prefix
84+
MATH(EXPR _prefix_start "${_lb_pos} + 4")
85+
STRING(SUBSTRING "${_pattern}" ${_prefix_start} -1 _after_lb)
86+
STRING(FIND "${_after_lb}" ")" _lb_end)
87+
STRING(SUBSTRING "${_after_lb}" 0 ${_lb_end} _lb_prefix)
88+
89+
# Extract the bare match (after the closing paren)
90+
MATH(EXPR _bare_start "${_lb_end} + 1")
91+
STRING(SUBSTRING "${_after_lb}" ${_bare_start} -1 _bare_pattern)
92+
93+
# Unescape BRE special chars for literal matching
94+
STRING(REPLACE "\\." "." _bare_pattern "${_bare_pattern}")
95+
STRING(REPLACE "\\*" "*" _bare_pattern "${_bare_pattern}")
96+
STRING(REPLACE "\\/" "/" _bare_pattern "${_bare_pattern}")
97+
98+
# Unescape replacement too
99+
STRING(REPLACE "\\." "." _replacement "${_replacement}")
100+
STRING(REPLACE "\\*" "*" _replacement "${_replacement}")
101+
STRING(REPLACE "\\/" "/" _replacement "${_replacement}")
102+
103+
# The already-qualified form is prefix + bare_pattern
104+
SET(_qualified
105+
"${_lb_prefix}${_bare_pattern}"
106+
)
107+
108+
# Three-pass workaround:
109+
SET(_placeholder
110+
"@@RV_SED_PLACEHOLDER_${_placeholder_counter}@@"
111+
)
112+
MATH(EXPR _placeholder_counter "${_placeholder_counter} + 1")
113+
114+
# Pass 1: Protect already-qualified occurrences
115+
STRING(REPLACE "${_qualified}" "${_placeholder}" _content "${_content}")
116+
# Pass 2: Qualify all remaining bare occurrences
117+
STRING(REPLACE "${_bare_pattern}" "${_replacement}" _content "${_content}")
118+
# Pass 3: Restore protected occurrences
119+
STRING(REPLACE "${_placeholder}" "${_qualified}" _content "${_content}")
120+
ELSE()
121+
# Literal replacement — unescape BRE special chars
122+
STRING(REPLACE "\\." "." _pattern "${_pattern}")
123+
STRING(REPLACE "\\*" "*" _pattern "${_pattern}")
124+
STRING(REPLACE "\\/" "/" _pattern "${_pattern}")
125+
126+
STRING(REPLACE "${_pattern}" "${_replacement}" _content "${_content}")
127+
ENDIF()
128+
ENDFOREACH()
129+
130+
FILE(
131+
WRITE "${OUTPUT_FILE}"
132+
"${_content}"
133+
)

src/lib/mu/MuQt5/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,9 @@ ADD_CUSTOM_COMMAND(
323323
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy_filtered.hpp
324324
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy.cpp
325325
COMMAND
326-
bash -c
327-
"sed -f ${CMAKE_CURRENT_SOURCE_DIR}/signalspy.sed ${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy.cpp >${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy_filtered.hpp"
326+
${CMAKE_COMMAND} -DINPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy.cpp
327+
-DOUTPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy_filtered.hpp -DSED_FILE=${CMAKE_CURRENT_SOURCE_DIR}/signalspy.sed -P
328+
${PROJECT_SOURCE_DIR}/cmake/scripts/apply_sed_filter.cmake
328329
COMMENT "Patching the moc_SignalSpy.cpp file ..."
329330
)
330331

src/lib/mu/MuQt6/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,9 @@ ADD_CUSTOM_COMMAND(
321321
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy_filtered.hpp
322322
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy.cpp
323323
COMMAND
324-
bash -c
325-
"sed -f ${CMAKE_CURRENT_SOURCE_DIR}/signalspy.sed ${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy.cpp >${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy_filtered.hpp"
324+
${CMAKE_COMMAND} -DINPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy.cpp
325+
-DOUTPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${_target}/generated/moc_SignalSpy_filtered.hpp -DSED_FILE=${CMAKE_CURRENT_SOURCE_DIR}/signalspy.sed -P
326+
${PROJECT_SOURCE_DIR}/cmake/scripts/apply_sed_filter.cmake
326327
COMMENT "Patching the moc_SignalSpy.cpp file ..."
327328
)
328329

0 commit comments

Comments
 (0)