-
Notifications
You must be signed in to change notification settings - Fork 366
Document how to get a MSVCRTD-based debug-build LIB on Windows #880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Ran into the same issue (windows, clang-cl), in debug mode you either have to compile the c++ part with |
@uazu Were you able to get a /Mtd build by setting the CFLAGS ? It might be simple but how to set such CFLAGS in cargo? |
Yes, we're still successfully building that way. Since this is a C++ project that calls Rust, we're setting CFLAGS in CMake, since that's the top-level tool that is building both the C++ code and the Rust code. (Don't ask me about CMake though.) |
First♥ cxx.rs !!! DisclaimerI'm a noob on this tech stack and certainly don't have the audacity to claim I can properly document this for CXX. This ticket was instrumental in solving my problems, though I had to scrape the solution together from many places and want to help out those that come after me. Sorry for the lengthy text. ContextI'm attempting to build a Rust It will deploy on Linux but it will be hard to pull Cpp devs away from their Visual Studio, so debugging needs to work on Windows & MSVC. FYI: only generating the Cpp files with Cxx without compiling them along is done with this in cxx_build::bridge("src/lib.rs").expand(); SymptomsI first started out with using a release build on the Rust side and unknowingly combined it with a Debug build on the MSVC side. When using function CxxString::to_string_lossy() it resulted in panic:
I thought I was running in to this mixed release/debug bug, but running it with a debug build only changed the panic:
Because of this. AnalysisTook me a while to figure out that statement requires the pointer to be aligned and non-null was a red herring. What's actually happening is that CxxString::len() was returning garbage (either Eventually I suspected that this was some mix of release and debug Microsoft runtimes and when running it in a debugger with module load logging that indeed pop-up.
Notice So it turns out that trying to read an Wait a minute, where does this Cpp runtime come from? Didn't you say you put the contract boundary on the C-ABI. Yes, but it turns out that Cxx internally still uses some Cpp to read the length from that SolutionBuilding Cxx with debug runtimesThis is where this ticket comes in. So setting those env vars seems to be the (only) way to achieve this. The most clean vanilla cargo solution I could come up with drew inspiration from here.
[alias]
bwindbg = "--config .cargo/bwindbg-config.toml build --target x86_64-pc-windows-msvc"
bwinrel = "build --release --target x86_64-pc-windows-msvc"
blindbg = "build --target x86_64-unknown-linux-gnu"
blinrel = "build --release --target x86_64-unknown-linux-gnu"
[env]
CFLAGS = "/MDd"
CXXFLAGS = "/MDd" Note that I'm using C++17 below so should do the same here.
[dependencies]
cxx = { version = "1.0", default-features = false, features = ["c++17", "std"] } Which then hits a variant of this issue during
Linking the debug runtimeSo this fix should have solved it, but it kept on failing. What I did notice is that cargo/rustc kept on inserting I was running rust Here's my working if env::var("TARGET").is_ok_and(|s| s.contains("windows-msvc")) {
// MSVC compiler suite
if env::var("CFLAGS").is_ok_and(|s| s.contains("/MDd")) {
// debug runtime flag is set
// Don't link the default CRT
println!("cargo::rustc-link-arg=/nodefaultlib:msvcrt");
// Link the debug CRT instead
println!("cargo::rustc-link-arg=/defaultlib:msvcrtd");
}
} CMake Cpp projectGiven that my CMake project is essentially a collage it seems only fair to share it too. cmake_minimum_required(VERSION 3.10)
project(my-examples-cpp)
# init - Linux Make GCC: Debug; Windows MSVC: Debug + Release
# cmake -S . -B build
# init - Windows Ninja Clang: Debug
# first run Visual Studio 2022 Developer Command Prompt
# "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
# then
# cmake -S . -G "Ninja" -B build-clang -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
# init - Make|Ninja: Release
# <init debug> -D CMAKE_BUILD_TYPE=Release
# build - Make: as inited; Windows MSVC: Debug
# cmake --build build
# build - Ninja: as inited
# cmake --build build-clang
# build - Windows MSVC: Release
# cmake --build build --config Release
set(CMAKE_CXX_STANDARD 17)
if (WIN32)
set(RUST_TARGET ${CMAKE_CURRENT_SOURCE_DIR}/lib/x86_64-pc-windows-msvc)
set(MY_LIB_NAME my_cxx.dll.lib)
if (MSVC)
# using UTF-8 source
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8")
endif()
else()
set(RUST_TARGET ${CMAKE_CURRENT_SOURCE_DIR}/lib/x86_64-unknown-linux-gnu)
set(MY_LIB_NAME libmy_cxx.so)
endif()
include_directories(${RUST_TARGET}/cxxbridge/my-cxx/src)
add_executable(my-examples-cpp src/main.cpp ${RUST_TARGET}/cxxbridge/my-cxx/src/lib.rs.cc)
# Link the dynamic library
if(CMAKE_CONFIGURATION_TYPES)
# https://stackoverflow.com/a/2224732/574370
target_link_libraries(my-examples-cpp debug ${RUST_TARGET}/debug/${MY_LIB_NAME})
target_link_libraries(my-examples-cpp optimized ${RUST_TARGET}/release/${MY_LIB_NAME})
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
target_link_libraries(my-examples-cpp ${RUST_TARGET}/release/${MY_LIB_NAME})
else()
target_link_libraries(my-examples-cpp ${RUST_TARGET}/debug/${MY_LIB_NAME})
endif() Obviously you have to figure out your own paths there. I lost quite a bit of time over the Don't forgetTo make sure your custom built ConclusionIf all those pieces of the puzzle fall in to place, now |
This took us a while to figure out. A Rust "staticlib" debug-build outputs a LIB which references MSVCRT. This is not suitable for linking with C++ code built using MSVC debug settings (/MDd), which requires everything to use only MSVCRTD. To get a Rust LIB which references MSVCRTD appears to require
CFLAGS=-MDd
andCXXFLAGS=-MDd
set in the Windows environment (e.g.set CFLAGS=-MDd
etc at CMD prompt). This works becausecc
crate picks these up when it callscl.exe
. In our use-case this caused all the mentions of MSVCRT in thedumpbin /all
output for the generated LIB to be replaced with MSVCRTD. Then the link of the LIB to debug C++ code succeeds.So the question is where this should be documented. It is no use documenting this in
cc
crate, because that is deep down the crate tree and no-one is going to look there. Perhaps people don't even realize thatcc
crate is being used. Since it's often someone directly usingcxx
crate to interface to C++ who would hit this problem, it would likely be helpful to document it in thecxx.rs
pages.(Thanks for
cxx
crate, by the way -- it helped us a lot!)The text was updated successfully, but these errors were encountered: