code duplication in cmake for sanitizer tests

Good day,

As part of a project of moving libFuzzer to compiler-rt I am trying to port libFuzzer tests to the new system.
I have a question about CMake structure for sanitizer tests:
compilation macros across different sanitizers are structured in almost-the-same-but-not-quite-way.
For instance, across tsan/msan/asan/xray we have:

1 # tsan_compile(obj_list, source, arch, {headers})
2 macro(tsan_compile obj_list source arch)
3 get_filename_component(basename ${source} NAME)
4 set(output_obj “${basename}.${arch}.o”)
5 get_target_flags_for_arch(${arch} TARGET_CFLAGS)
6 set(COMPILE_DEPS ${TSAN_RTL_HEADERS} ${ARGN})
7 if(NOT COMPILER_RT_STANDALONE_BUILD)
8 list(APPEND COMPILE_DEPS gtest tsan)
9 endif()
10 clang_compile(${output_obj} ${source}
11 CFLAGS ${TSAN_UNITTEST_CFLAGS} ${TARGET_CFLAGS}
12 DEPS ${COMPILE_DEPS})
13 list(APPEND ${obj_list} ${output_obj})
14 endmacro()

1 # Compile source for the given architecture, using compiler
2 # options in ${ARGN}, and add it to the object list.
3 macro(asan_compile obj_list source arch kind)
4 get_filename_component(basename ${source} NAME)
5 if(CMAKE_CONFIGURATION_TYPES)
6 set(output_obj “${CMAKE_CFG_INTDIR}/${obj_list}.${basename}.${arch}${kind}.o”)
7 else()
8 set(output_obj “${obj_list}.${basename}.${arch}${kind}.o”)
9 endif()
10 get_target_flags_for_arch(${arch} TARGET_CFLAGS)
11 set(COMPILE_DEPS ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE})
12 if(NOT COMPILER_RT_STANDALONE_BUILD)
13 list(APPEND COMPILE_DEPS gtest asan)
14 endif()
15 clang_compile(${output_obj} ${source}
16 CFLAGS ${ARGN} ${TARGET_CFLAGS}
17 DEPS ${COMPILE_DEPS})
18 list(APPEND ${obj_list} ${output_obj})
19 endmacro()

1 # Compile source for the given architecture, using compiler
2 # options in ${ARGN}, and add it to the object list.
3 macro(msan_compile obj_list source arch kind)
4 get_filename_component(basename ${source} NAME)
5 set(output_obj “${basename}.${arch}${kind}.o”)
6 get_target_flags_for_arch(${arch} TARGET_CFLAGS)
7 set(COMPILE_DEPS ${MSAN_UNITTEST_HEADERS})
8 if(NOT COMPILER_RT_STANDALONE_BUILD)
9 list(APPEND COMPILE_DEPS gtest msan)
10 endif()
11 clang_compile(${output_obj} ${source}
12 CFLAGS ${ARGN} ${TARGET_CFLAGS}
13 DEPS ${COMPILE_DEPS})
14 list(APPEND ${obj_list} ${output_obj})
15 endmacro()

1 macro(xray_compile obj_list source arch)
2 get_filename_component(basename ${source} NAME)
3 set(output_obj “${basename}.${arch}.o”)
4 get_target_flags_for_arch(${arch} TARGET_CFLAGS)
5 if(NOT COMPILER_RT_STANDALONE_BUILD)
6 list(APPEND COMPILE_DEPS gtest_main xray)
7 endif()
8 clang_compile(${output_obj} ${source}
9 CFLAGS ${XRAY_UNITTEST_CFLAGS} ${TARGET_CFLAGS}
10 DEPS ${COMPILE_DEPS})
11 list(APPEND ${obj_list} ${output_obj})
12 endmacro()

The code is duplicated, yet with minor differences, begging question e.g. why CMAKE_CFG_INTDIR path workaround is applied to asan, but not to others.

For future libraries in compiler-rt, should yet fifth copy of the function be added, or would it be better to extract it into a common macro which could be reused?
I can do the latter if agreed that it is a good idea.

George

I think both ‘extract to common’ and ‘fifth copy’ would be fine here, up to you.