Skip to content

Commit 3da8b58

Browse files
narknonjschwe
andauthored
Fix output directory handling with $<CONFIG> (corrosion-rs#631)
* Fixes output directory handling for generator expressions Ensures that the configuration subdirectory is only appended to the output directory if the specified output directory does not already contain a generator expression. This mirrors the logic from _corrosion_set_imported_location_deferred. This prevents incorrect path construction when generator expressions are used to define output paths. * Add Test for $<CONFIG> in output directory * Fix $<CONFIG> in single-config generators --------- Co-authored-by: Jonathan Schwender <schwenderjonathan@gmail.com>
1 parent e8b2d68 commit 3da8b58

File tree

8 files changed

+111
-17
lines changed

8 files changed

+111
-17
lines changed

cmake/Corrosion.cmake

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,26 @@ function(_corrosion_bin_target_suffix target_name out_var_suffix)
114114
set(${out_var_suffix} "${_suffix}" PARENT_SCOPE)
115115
endfunction()
116116

117+
function(_handle_output_directory_genex input_path config_type output_path)
118+
if("${config_type}" STREQUAL "")
119+
# Prevent new path from being `dir//file`, since that causes issues with the
120+
# file dependency.
121+
string(REPLACE "/\$<CONFIG>" "${config_type}" curr_out_dir "${input_path}")
122+
string(REPLACE "\$<CONFIG>" "${config_type}" curr_out_dir "${curr_out_dir}")
123+
else()
124+
string(REPLACE "\$<CONFIG>" "${config_type}" curr_out_dir "${input_path}")
125+
endif()
126+
string(GENEX_STRIP "${curr_out_dir}" stripped_out_dir)
127+
if("${stripped_out_dir}" STREQUAL "${curr_out_dir}")
128+
set("${output_path}" "${curr_out_dir}" PARENT_SCOPE)
129+
else()
130+
unset("${output_path}" PARENT_SCOPE)
131+
message(WARNING "Encountered output directory path with unsupported genex. "
132+
"Output dir: `${curr_out_dir}`"
133+
"Note: Corrosion only supports the `\$<CONFIG>` generator expression for output directories.")
134+
endif()
135+
endfunction()
136+
117137
# Do not call this function directly!
118138
#
119139
# This function should be called deferred to evaluate target properties late in the configure stage.
@@ -159,12 +179,8 @@ function(_corrosion_set_imported_location_deferred target_name base_property out
159179
else()
160180
set(curr_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
161181
endif()
162-
string(REPLACE "\$<CONFIG>" "${config_type}" curr_out_dir "${curr_out_dir}")
163-
message(DEBUG "Setting ${base_property}_${config_type_upper} for target ${target_name}"
164-
" to `${curr_out_dir}/${filename}`.")
165-
166-
string(GENEX_STRIP "${curr_out_dir}" stripped_out_dir)
167-
if(NOT ("${stripped_out_dir}" STREQUAL "${curr_out_dir}"))
182+
_handle_output_directory_genex("${curr_out_dir}" "${config_type}" sanitized_out_dir)
183+
if(NOT DEFINED sanitized_out_dir)
168184
message(FATAL_ERROR "${output_directory_property} for target ${output_dir_prop_target_name} "
169185
"contained an unexpected Generator expression. Output dir: `${curr_out_dir}`"
170186
"Note: Corrosion only supports the `\$<CONFIG>` generator expression for output directories.")
@@ -174,9 +190,9 @@ function(_corrosion_set_imported_location_deferred target_name base_property out
174190
set_property(
175191
TARGET ${target_name}
176192
PROPERTY "${base_property}_${config_type_upper}"
177-
"${curr_out_dir}/${filename}"
193+
"${sanitized_out_dir}/${filename}"
178194
)
179-
set(base_output_directory "${curr_out_dir}")
195+
set(base_output_directory "${sanitized_out_dir}")
180196
endforeach()
181197

182198
if(NOT COR_IS_MULTI_CONFIG)
@@ -185,13 +201,13 @@ function(_corrosion_set_imported_location_deferred target_name base_property out
185201
else()
186202
set(base_output_directory "${CMAKE_CURRENT_BINARY_DIR}")
187203
endif()
188-
string(REPLACE "\$<CONFIG>" "${CMAKE_BUILD_TYPE}" base_output_directory "${base_output_directory}")
189-
string(GENEX_STRIP "${base_output_directory}" stripped_out_dir)
190-
if(NOT ("${stripped_out_dir}" STREQUAL "${base_output_directory}"))
204+
_handle_output_directory_genex("${base_output_directory}" "${CMAKE_BUILD_TYPE}" sanitized_output_directory)
205+
if(NOT DEFINED sanitized_output_directory)
191206
message(FATAL_ERROR "${output_dir_prop_target_name} for target ${output_dir_prop_target_name} "
192-
"contained an unexpected Generator expression. Output dir: `${base_output_directory}`"
207+
"contained an unexpected Generator expression. Output dir: `${base_output_directory}`."
193208
"Note: Corrosion only supports the `\$<CONFIG>` generator expression for output directories.")
194209
endif()
210+
set(base_output_directory "${sanitized_output_directory}")
195211
endif()
196212

197213
message(DEBUG "Setting ${base_property} for target ${target_name}"
@@ -259,10 +275,15 @@ function(_corrosion_copy_byproduct_deferred target_name output_dir_prop_names ca
259275
if(output_dir_curr_config)
260276
set(curr_out_dir "${output_dir_curr_config}")
261277
elseif(output_dir)
262-
# Fallback to `output_dir` if specified
263-
# Note: Multi-configuration generators append a per-configuration subdirectory to the
264-
# specified directory unless a generator expression is used (from CMake documentation).
265-
set(curr_out_dir "${output_dir}/${config_type}")
278+
string(GENEX_STRIP "${output_dir}" output_dir_no_genex)
279+
# Only add config dir if there is no genex in here. See
280+
# https://cmake.org/cmake/help/latest/prop_tgt/RUNTIME_OUTPUT_DIRECTORY.html
281+
# Logic duplicated from _corrosion_set_imported_location_deferred
282+
if(output_dir STREQUAL output_dir_no_genex)
283+
set(curr_out_dir "${output_dir}/${config_type}")
284+
else()
285+
set(curr_out_dir "${output_dir}")
286+
endif()
266287
else()
267288
# Fallback to the default directory. We do not append the configuration directory here
268289
# and instead let CMake do this, since otherwise the resolving of dynamic library

test/output directory/CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ add_test(NAME "output_directory_build"
3232
CARGO_TARGET "${Rust_CARGO_TARGET}"
3333
SYSTEM_NAME "${CMAKE_SYSTEM_NAME}"
3434
${configure_cmake_args}
35-
3635
COMMAND_EXPAND_LISTS
3736
)
3837
set_tests_properties("output_directory_build" PROPERTIES FIXTURES_SETUP "build_fixture_output_directory")
@@ -159,4 +158,14 @@ set_tests_properties("postbuild_custom_command" PROPERTIES FIXTURES_REQUIRED "bu
159158
add_test(NAME "output_directory_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build")
160159
set_tests_properties("output_directory_cleanup" PROPERTIES FIXTURES_CLEANUP "build_fixture_output_directory")
161160

161+
####################################
162+
# output_directory_config
163+
####################################
164+
165+
166+
corrosion_tests_add_test(output_directory_config "consumer")
167+
168+
set_tests_properties("output_directory_config_run_consumer" PROPERTIES PASS_REGULAR_EXPRESSION
169+
"^Hello from output_directory_config_test_executable"
170+
)
162171

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
cmake_minimum_required(VERSION 3.15)
2+
project(test_project VERSION 0.1.0)
3+
include(../../test_header.cmake)
4+
5+
corrosion_import_crate(MANIFEST_PATH proj1/Cargo.toml)
6+
7+
# Note: The output directories defined here must be manually kept in sync with the expected test location.
8+
set_target_properties(rust_bin1
9+
PROPERTIES
10+
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/bin"
11+
PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/bin"
12+
)
13+
14+
set_target_properties(rust_lib1 PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/lib")
15+
set_target_properties(rust_lib1
16+
PROPERTIES
17+
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/lib"
18+
PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/lib"
19+
)
20+
21+
add_executable(consumer consumer.cpp)
22+
add_dependencies(consumer cargo-build_rust_lib1)
23+
target_link_libraries(consumer rust_lib1)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <iostream>
2+
#include <cstdlib>
3+
4+
extern "C" unsigned int ret_12();
5+
6+
7+
int main(int argc, char *argv[])
8+
{
9+
std::cout << "Hello from output_directory_config_test_executable\n";
10+
unsigned int a = ret_12();
11+
if (a != 12) {
12+
return -1;
13+
}
14+
15+
return 0;
16+
}

test/output directory/output_directory_config/proj1/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "rust_package1"
3+
version = "0.1.0"
4+
edition = "2018"
5+
6+
[lib]
7+
name = "rust_lib1"
8+
crate-type=["staticlib", "cdylib"]
9+
10+
[[bin]]
11+
name = "rust_bin1"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
println!("Hello, world from test rust binary");
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[no_mangle]
2+
pub extern "C" fn ret_12() -> u32 {
3+
12
4+
}

0 commit comments

Comments
 (0)