cmake-rs icon indicating copy to clipboard operation
cmake-rs copied to clipboard

Need to add /build/Release with visual studio 2015 update 3

Open Stargateur opened this issue 7 years ago • 6 comments

here my build.rs

extern crate cmake;

fn main() {
    let dst = cmake::Config::new("librtmp").build_target("rtmp").build();

    if cfg!(any(windows)) {
        println!("cargo:rustc-link-search=native={}/build/Release", dst.display());
    }
    else {
        println!("cargo:rustc-link-search=native={}/build", dst.display());
    }
    println!("cargo:rustc-link-lib=static=rtmp");
}

if I don't add "/build/Release". I get the following error

error: could not find native static library `rtmp`, perhaps an -L flag is missing?

but it's work fine with it.

and on linux i need to add /build

It's a bug or I do it wrong ?

my cmake

cmake_minimum_required(VERSION 3.0)
project(librtmp)
add_library(rtmp
  STATIC
  rtmp.c
  log.c
  amf.c
  hashswf.c
  parseurl.c
  amf.h
  bytes.h
  dh.h
  dhgroups.h
  handshake.h
  http.h
  log.h
  rtmp_sys.h
  rtmp.h
)
if(WIN32)
  target_link_libraries(rtmp PUBLIC ws2_32)
endif()
target_compile_definitions(rtmp PUBLIC -DNO_CRYPTO)

Stargateur avatar Oct 26 '16 23:10 Stargateur

I will say I've been baffled by this in the past as well. Unfortunately I actually know very little about cmake itself, but it seems like this is expected behavior from the various generators?

alexcrichton avatar Oct 27 '16 14:10 alexcrichton

It seems that multi-configuration generators like MSVC always create a sub-folder like Debug or Release. I didn't find any way to change that or get the path to the target in CMakeList.txt https://cmake.org/cmake/help/latest/policy/CMP0026.html.

by the way you do let build = dst.join("build"); but you do return dst so dst.display() doesn't return the directory to cmake build.

Stargateur avatar Nov 04 '16 07:11 Stargateur

Running into this as well; given that this issue was around for >2 years, I wonder how other people work around this...

RReverser avatar Jan 11 '19 17:01 RReverser

I spent a long time scratching my about this, and I've finally figured this out. I think it is best categorized as a "usage error", and not a true bug, though the documentation should certainly describe how to avoid the error.

The problem comes down to whether CMake is properly being asked to "install" the tool, or just "build" it. I'm going to take the rdkafka-sys crate as an example, since that's what I'm most familiar with. Until recently, we were asking CMake to build the rdkafka target:

https://github.com/fede1024/rust-rdkafka/blob/d159783c0796159497302ea72ede74d6bfd7d297/rdkafka-sys/build.rs#L176

and then telling Rust to go find the library out of the target/debug/build/rdkafka-sys-HASH/out/build/src folder. Of course, this didn't work with MSVC for the reasons described here, as the compiled artifacts would end up in build/Debug/src or build/RelWithDebInfo. We had a patch the tried to append this configuration name as necessary (https://github.com/fede1024/rust-rdkafka/commit/5cd9c033083c871ce4334c3bf5995afd1ab65e44), but it was buggy (https://github.com/fede1024/rust-rdkafka/issues/191).

In general, the approach of trying to figure out where CMake is going to generate files in the build tree is unworkable! CMake is best treated as a black box. While there is a CMake variable called CMAKE_CFG_INTDIR that tells you about whether this magic Debug or RelWithDebInfo directory is going to exist, and if so what its name is, that variable is completely inaccessible outside of a CMake script itself.

The solution is to ask CMake to actually install the project, at which point CMake will make some promises to you. Libraries will go into CMAKE_INSTALL_PREFIX/lib, headers will go into CMAKE_INSTALL_PREFIX/include. This crate is already equipped to set CMAKE_INSTALL_PREFIX to target/debug/build/rdkafka-sys-HASH, so that things don't actually get installed into, say, /usr/local, which would obviously be a disaster. Then we just point Rust at OUT_DIR/lib, where we know the library will exist, regardless of whether the CMake generator used an extra directory in the build path or not:

https://github.com/fede1024/rust-rdkafka/blob/e86996919f6bc37aabe3dc9fa1c99cfa9ba269e4/rdkafka-sys/build.rs#L231

If a particular project is not installing its libraries into CMAKE_INSTALL_PREFIX/lib, that is most definitely a bug in that project's CMake configuration and should be filed as such with the project.

tl;dr if your project is calling .build_target("something other than install"), it is probably wrong, and using the install target with an appropriately-adjusted rustc-link-search path will likely fix the issue.

benesch avatar Dec 11 '19 06:12 benesch

I spent a long time scratching my about this, and I've finally figured this out. I think it is best categorized as a "usage error", and not a true bug, though the documentation should certainly describe how to avoid the error.

The problem comes down to whether CMake is properly being asked to "install" the tool, or just "build" it. I'm going to take the rdkafka-sys crate as an example, since that's what I'm most familiar with. Until recently, we were asking CMake to build the rdkafka target:

https://github.com/fede1024/rust-rdkafka/blob/d159783c0796159497302ea72ede74d6bfd7d297/rdkafka-sys/build.rs#L176

and then telling Rust to go find the library out of the target/debug/build/rdkafka-sys-HASH/out/build/src folder. Of course, this didn't work with MSVC for the reasons described here, as the compiled artifacts would end up in build/Debug/src or build/RelWithDebInfo. We had a patch the tried to append this configuration name as necessary (fede1024/rust-rdkafka@5cd9c03), but it was buggy (fede1024/rust-rdkafka#191).

In general, the approach of trying to figure out where CMake is going to generate files in the build tree is unworkable! CMake is best treated as a black box. While there is a CMake variable called CMAKE_CFG_INTDIR that tells you about whether this magic Debug or RelWithDebInfo directory is going to exist, and if so what its name is, that variable is completely inaccessible outside of a CMake script itself.

The solution is to ask CMake to actually install the project, at which point CMake will make some promises to you. Libraries will go into CMAKE_INSTALL_PREFIX/lib, headers will go into CMAKE_INSTALL_PREFIX/include. This crate is already equipped to set CMAKE_INSTALL_PREFIX to target/debug/build/rdkafka-sys-HASH, so that things don't actually get installed into, say, /usr/local, which would obviously be a disaster. Then we just point Rust at OUT_DIR/lib, where we know the library will exist, regardless of whether the CMake generator used an extra directory in the build path or not:

https://github.com/fede1024/rust-rdkafka/blob/e86996919f6bc37aabe3dc9fa1c99cfa9ba269e4/rdkafka-sys/build.rs#L231

If a particular project is not installing its libraries into CMAKE_INSTALL_PREFIX/lib, that is most definitely a bug in that project's CMake configuration and should be filed as such with the project.

tl;dr if your project is calling .build_target("something other than install"), it is probably wrong, and using the install target with an appropriately-adjusted rustc-link-search path will likely fix the issue.

thanks a lot for this explainer. I really think this crate should include an example cmakelists.txt for cmake noobs like me.

anzbert avatar Oct 17 '22 14:10 anzbert

Thx @benesch for the hint!

so should you always install, for example static libraries to CMAKE_INSTALL_PREFIX/lib ?

eg. like so, at the end of my cmakelists.txt:

install(TARGETS example_lib 
        "${CMAKE_INSTALL_PREFIX}/lib")

this seems to work as well:

install(TARGETS example_lib 
        "./lib")

which one is preferable?

Thanks!!

anzbert avatar Oct 17 '22 15:10 anzbert