Hi!
There is a multilanguage project that cries out for CMake, and Rust is one of them, but I would save ourselves from using muliple flavors of make. (Note that I am not the author of the Rust sources, I am just responsible for holding the project together. There are several developers, each responsible for one language.)
There is a manybody-rust-common.rs crate that holds common functionality for all executables, one being parsing arguements using getopts. Then there are multiple executables manybody-rust-v0, v1, v2, etc. that use this common crate.
What is the best way to compile this? In a C/C++ world I would compile manybody-rust-common to a dynamic or static library and link to it. The author of the Rust sources is a Rust newbie and has a hard time answering what Cargo and rustc under the hood are doing (which I do not blame him for, as Rust on Windows is not trivial). He came up with the following Cargo script:
[package]
name = "manybody"
version = "0.0.1"
authors = ["Email here"]
[[bin]]
name = "manybody0"
path = "src/manybody0.rs"
[[bin]]
name = "manybody1"
path = "src/manybody1.rs"
...
[dependencies]
getopts = "*"
This compiles just fine. Trying to build this with CMake, I came up with the following script using the RustCMake module for the common part:
project (manybody-rust-common)
set (Project_Base_Dir ../../manybody/)
set (CMAKE_USE_RELATIVE_PATH "true")
set (Files_SRCS)
set (Files_SRCS ${Project_Base_Dir}/src/comp_phys_common.rs)
set (Files_BUILD ${Files_SRCS})
# Create filters for IDEs
source_group ("Sources" FILES ${Files_SRCS})
# Get the dependencies of all the crates
get_rust_deps(${Files_SRCS} manybody-rust-common_DEPS COMPILE)
# Build the library
rust_crate(${Files_SRCS}
ALL
TARGET_NAME ${PROJECT_NAME}
DESTINATION lib/${CONFIGURATION_NAME})
DEPENDS "${manybody-rust-common_DEPS}")
And this is the script for the v0 executable:
project (manybody-rust-v0)
set (Project_Base_Dir ../../manybody/)
set (CMAKE_USE_RELATIVE_PATH "true")
set (Files_SRCS)
set (Files_SRCS ${Project_Base_Dir}/src/manybody0.rs)
set (Files_BUILD ${Files_SRCS})
# Create filters for IDEs
source_group ("Sources" FILES ${Files_SRCS})
# Get the dependencies of all the crates
get_rust_deps(${Files_SRCS} manybody-rust-v0_DEPS)
# Build examples
rust_crate(${Files_SRCS}
ALL
TARGET_NAME ${PROJECT_NAME}
DESTINATION bin/${CONFIGURATION_NAME}
DEPENDS "${manybody-rust-common_FULL_TARGET};${manybody-rust-v0_DEPS}")
However when I try to build my project, this is what I get:
C:/Users/nagy-_000/Git/comp-phys/manybody/rust/cmake/common/../../manybody//src/comp_phys_common.rs:32:37: 32:53 error: use of undeclared type name `getopts::Options`
C:/Users/nagy-_000/Git/comp-phys/manybody/rust/cmake/common/../../manybody//src/comp_phys_common.rs:32 fn print_usage(program: &str, opts: getopts::Options) {
^~~~~~~~~~~~~~~~
C:/Users/nagy-_000/Git/comp-phys/manybody/rust/cmake/common/../../manybody//src/comp_phys_common.rs:42:20: 42:41 error: failed to resolve. Could not find `Options` in `getopts`
C:/Users/nagy-_000/Git/comp-phys/manybody/rust/cmake/common/../../manybody//src/comp_phys_common.rs:42 let mut opts = getopts::Options::new();
^~~~~~~~~~~~~~~~~~~~~
C:/Users/nagy-_000/Git/comp-phys/manybody/rust/cmake/common/../../manybody//src/comp_phys_common.rs:42:20: 42:41 error: unresolved name `getopts::Options::new`
C:/Users/nagy-_000/Git/comp-phys/manybody/rust/cmake/common/../../manybody//src/comp_phys_common.rs:42 let mut opts = getopts::Options::new();
^~~~~~~~~~~~~~~~~~~~~
error: aborting due to 3 previous errors
NMAKE : fatal error U1077: 'C:\Kellekek\Open-Source\Rust\1.0.0-beta\bin\rustc.exe' : return code '0x65'
Stop.
NMAKE : fatal error U1077: '"C:\Kellekek\Microsoft\Visual Studio\14.0\VC\BIN\amd64\nmake.exe"' : return code '0x2'
Stop.
NMAKE : fatal error U1077: '"C:\Kellekek\Microsoft\Visual Studio\14.0\VC\BIN\amd64\nmake.exe"' : return code '0x2'
Stop.
- How can I alter my CMake scripts so that it correctly picks up getopts and common?
- The RustCMake example script shows how to add unit test, but that does not integrate with the native unit test mechanism, which we do employ for all the other languages. Can the Rust executables integrate to the other tests? (in the native test target?)
Rust is a hell of a language with enormous potential, but I detest how strongly the means of compiling and distributing Rust interacts with the language itself. #pragma lib() is the evil counterpart to this in C++. Source code should have nothing to do with how I want to compile an application. Source code should not contain filenames, neither should a build system depend on directory structure or file naming conventions. It seems Rust has taken a direction where it is getting harder and harder to compile Rust without Cargo. Why should I, a package maintainer (so to say) have to learn a whole new make language just because it goes hand-in-hand with a language? Rust is not born into vacuum, and I think the community should focus more on Rust integrating with other tools, such as the VS Add-In, and RustCMake. If not promote, at least mention them on rust-lang.org.