Skip to content
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

Windows - MinGW gcc: Compiled object always gets put in the root project directory #819

Closed
Spencer1O1 opened this issue Jul 17, 2023 · 4 comments

Comments

@Spencer1O1
Copy link
Contributor

The issue:

I have a C file in the root of my Rust project: my_interop.c (the issue persists wherever I place it)
My build.rs script, about as simple as it can get, looks like this:

fn main() {
    cc::Build::new()
        .file("my_interop.c")
        .compile("my_interop");
    println!("cargo:rustc-link-lib=user32"); // my_interop.c includes <windows.h>
}

When building, the log says,

running: "C:\\MinGW\\bin\\gcc.exe" "-O0" "-ffunction-sections" "-fdata-sections" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-FoC:\\Dev\\my-project\\target\\debug\\build\\my-project-4a742f3493d90fa9\\out\\my_interop.o" "-c" "my_interop.c"

which should put the object file in target/debug/build/my-project-.../out/get_wp_handle.o
However, I find the object file in the root directory, outside of target.

Then, in the linking step, the log says,

running: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.34.31933\\bin\\HostX64\\x64\\lib.exe" "-out:C:\\Dev\\my-project\\target\\debug\\build\\my-project-4a742f3493d90fa9\\out\\libmy_interop.a" "-nologo" "C:\\Dev\\my-project\\target\\debug\\build\\my-project-4a742f3493d90fa9\\out\\my_interop.o"
  LINK : fatal error LNK1181: cannot open input file 'C:\Dev\my-project\target\debug\build\my-project-4a742f3493d90fa9\out\my_interop.o'
  exit code: 1181

which is obviously because the object file got put in the root directory rather than the designated output directory.

In my build script I have tried adding .output_dir("some/specific/dir") but the object file still gets put at the root.

The temporary solution:

If I change my build script to be

fn main() {
    cc::Build::new()
        .file("my_interop.c")
        .out_dir(".")
        .compile("my_interop");
    println!("cargo:rustc-link-lib=user32"); // my_interop.c uses #include <windows.h>
}

the linking step will expect the object file to be in the root directory.
It compiles as needed, and the project runs fine.
However, now the issue is that all of the other output files get put there too.
We end up a bunch of junk like this,

<Dir>    .
<Dir>    ..
         .gitignore
         build.rs
         Cargo.lock
         Cargo.toml
         my_interop.c
         my_interop.lib
         my_interop.o
         libmy_interop.a
<Dir>    src
<Dir>    target

which isn't good for maintainability.

Full Log:

error: failed to run custom build command for `my-project v0.1.0 (C:\Dev\my-project)`

Caused by:
  process didn't exit successfully: `C:\Dev\my-project\target\debug\build\my-project-e6e1131d5fda03d6\build-script-build` (exit code: 1)
  --- stdout
  TARGET = Some("x86_64-pc-windows-msvc")
  OPT_LEVEL = Some("0")
  HOST = Some("x86_64-pc-windows-msvc")
  cargo:rerun-if-env-changed=CC_x86_64-pc-windows-msvc
  CC_x86_64-pc-windows-msvc = None
  cargo:rerun-if-env-changed=CC_x86_64_pc_windows_msvc
  CC_x86_64_pc_windows_msvc = None
  cargo:rerun-if-env-changed=HOST_CC
  HOST_CC = None
  cargo:rerun-if-env-changed=CC
  CC = Some("C:\\MinGW\\bin\\gcc.exe")
  cargo:rerun-if-env-changed=CFLAGS_x86_64-pc-windows-msvc
  CFLAGS_x86_64-pc-windows-msvc = None
  cargo:rerun-if-env-changed=CFLAGS_x86_64_pc_windows_msvc
  CFLAGS_x86_64_pc_windows_msvc = None
  cargo:rerun-if-env-changed=HOST_CFLAGS
  HOST_CFLAGS = None
  cargo:rerun-if-env-changed=CFLAGS
  CFLAGS = None
  cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
  CRATE_CC_NO_DEFAULTS = None
  DEBUG = Some("true")
  CARGO_CFG_TARGET_FEATURE = Some("fxsr,sse,sse2")
  running: "C:\\MinGW\\bin\\gcc.exe" "-O0" "-ffunction-sections" "-fdata-sections" "-g" "-fno-omit-frame-pointer" "-m64" "-Wall" "-Wextra" "-FoC:\\Dev\\my-project\\target\\debug\\build\\my-project-4a742f3493d90fa9\\out\\my_interop.o" "-c" "my_interop.c"
  exit code: 0
  cargo:rerun-if-env-changed=AR_x86_64-pc-windows-msvc
  AR_x86_64-pc-windows-msvc = None
  cargo:rerun-if-env-changed=AR_x86_64_pc_windows_msvc
  AR_x86_64_pc_windows_msvc = None
  cargo:rerun-if-env-changed=HOST_AR
  HOST_AR = None
  cargo:rerun-if-env-changed=AR
  AR = None
  cargo:rerun-if-env-changed=ARFLAGS_x86_64-pc-windows-msvc
  ARFLAGS_x86_64-pc-windows-msvc = None
  cargo:rerun-if-env-changed=ARFLAGS_x86_64_pc_windows_msvc
  ARFLAGS_x86_64_pc_windows_msvc = None
  cargo:rerun-if-env-changed=HOST_ARFLAGS
  HOST_ARFLAGS = None
  cargo:rerun-if-env-changed=ARFLAGS
  ARFLAGS = None
  running: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.34.31933\\bin\\HostX64\\x64\\lib.exe" "-out:C:\\Dev\\my-project\\target\\debug\\build\\my-project-4a742f3493d90fa9\\out\\libmy_interop.a" "-nologo" "C:\\Dev\\my-project\\target\\debug\\build\\my-project-4a742f3493d90fa9\\out\\my_interop.o"
  LINK : fatal error LNK1181: cannot open input file 'C:\Dev\my-project\target\debug\build\my-project-4a742f3493d90fa9\out\my_interop.o'
  exit code: 1181

I'm new to C and all of the compiling and linking, so I'm having trouble coming up with a solution. I'm not sure if this is a problem with cc-rs or gcc.

@Spencer1O1
Copy link
Contributor Author

After reading through some more issues, I think it is a problem with the -Fo flag on Windows instead of -o. This is still unresolved from issues #482 and #800

@Spencer1O1
Copy link
Contributor Author

I managed to fix this and submitted a pull request #820
Just waiting to get it merged

@dot-asm
Copy link
Contributor

dot-asm commented Jul 18, 2023

The fact that #820 worked for you is actually circumstantial. The trouble is that mingw gcc is free to generate references to symbols that are not available in msvc run-time. And when it does, it inevitably translates to linking errors later on. Simplest example is ___chkstk_ms used by mingw compiler when a subroutine allocates a stack frame larger than ~4K. "Ultimately elaborate" example would be C++ exceptions. With this in mind from maintainability viewpoint the most sensible thing to do is rather to reject unsupported $CC values, either by failing the compilation or ignoring the variable, naturally with a meaningful error or warning message with reference to --target=*-pc--windows-gnu as the supported way to engage with mingw gcc.

For reference. clang [not to be confused with clang-cl!] can target mingw, and the relevant question is what is the default for the one that gets invoked in any particular case. Default for clang bundled with Visual Studio is msvc, which works in the context, but the default for one installed in the mingw environment is mingw, which is error-prone for the above reasons. Given the ambiguity one can argue that it would be more than appropriate to complement the clang [again, not to be mixed up with clang-cl!] command with explicit --target=*-pc-windows-msvc flag when compiling for msvc.

@dot-asm
Copy link
Contributor

dot-asm commented Jul 18, 2023

And when it does, it inevitably translates to linking errors later on. ... C++ ...

BTW, gnu and msvc are using different name mangling schemes, so that any references to C++ run-time will end up unlinkable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants