-
Notifications
You must be signed in to change notification settings - Fork 709
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
[WIP] Port build system to use only build.rs on unix #321
Conversation
weiznich
commented
Oct 25, 2016
- Fix Build fails when there are spaces in the path to the project #320
4fa1148
to
3dd68d3
Compare
Any ideas why the windows builder is failing? |
Wow! Thanks for this! Three questions to start with:
|
I've developed the code to fix the issue with the white spaces. So unfortunately there is no history for this.
target_build_utils simplifies the handling of the target_triples. Especially it removes the parsing and unifying of those triples (For example it maps i586, i386 and i686 to x86). It should be possible to implement this without this crate, but it would result in quite a bit additional code that needs to be written. Furthermore it's only a build_dependency, which means its not added in the final library. Also target_build_utils and all of it's dependencies only contains pure rust code (as far as I can see). So it should build fine on every platform.
The gcc crate honors CC, CXX, AS, etc (and many more). It seems like it even detects if it's cross compiling to ios and sets the according sdk path. Take a look at the code for the compiler selection. We could also set the compiler manually using this function. |
@frewsxcv Do you have an opinion about this? My main concerns about this kind of switch are:
Despite those concerns, I think it makes sense to find a way to make the build work without requiring GNU make. |
crypto/test/bn_test_lib.c
Outdated
@@ -133,7 +133,7 @@ int BN_rand(BIGNUM *rnd, int bits, RAND *rng) { | |||
bit = (bits - 1) % 8; | |||
mask = 0xff << (bit + 1); | |||
|
|||
buf = OPENSSL_malloc(bytes); | |||
buf = (uint8_t*) OPENSSL_malloc(bytes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you add this cast? The policy so far is to not cast (void *)
since C doesn't require the cast, because in general we have a goal of eliminating every single cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried to compile this as c++ code. In this case g++ complains that void*
is no uint8_t*
.
error: invalid conversion from ‘void*’ to ‘uint8_t*‘[-fpermissive]
It's not needed now, so I've removed this from the current version.
crypto/constant_time_test.c
Outdated
@@ -42,6 +42,9 @@ | |||
* copied and put under another distribution licence | |||
* [including the GNU Public Licence.] | |||
*/ | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this change is important then please make it in a separate PR that explains why it was done. It shouldn't be needed, AFAICT.
build.rs
Outdated
"crypto/test/bn_test_lib.c", | ||
"crypto/test/file_test.cc"]; | ||
|
||
const C_FLAGS: &'static [&'static str] = &["-std=c1x", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this formatting the result of rustfmt
? It seems strange to indent this so far to the right, especially considering the other things aren't indented this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's produced by rustfmt
in this way. 😞
build.rs
Outdated
|
||
const AS_FLAGS: &'static [&'static str] = &["-Wa,--noexecstack,-gdwarf"]; | ||
|
||
const IOS_MIN_VERSION: &'static str = "7.0"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that all the stuff above, which are basically the options that control the build, should be at the top of this file. However, for the rest of the file, please organize things top-down: main, then build_msvc
, then the rest of the stuff sorted in your best judgement in a top-down manner. (This is the style in ring in general.)
build.rs
Outdated
println!("cargo:rerun-if-changed=build.rs"); | ||
} | ||
|
||
fn build_msvc(target_info: &TargetInfo, lib_path: PathBuf, disable_opt: bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please split the PR so that the build_msvc
function is factored out, with the original logic, in a separate commit.
build.rs
Outdated
.chain(RING_ARM_SRCS.iter()) | ||
.chain(RING_X86_64_SRC.iter()) | ||
.chain(RING_X86_SRCS.iter()) | ||
.chain(RING_INTEL_SHARED_SRCS.iter()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct? It seems we also need to consider all the header files in all directories, and crypto/sha/asm/sha-x86_64.pl
, in addition to the above.
It would be great if there were some way we could calculate the list of source files to track, and then traverse that list to do the actual build, instead of effectively calculating here and then also separately during the building.
For example, why not run through this iterator and call a "build_source" function that differentiates the type of source file by the extension, calling build_asm
or whatever?
build.rs
Outdated
} | ||
|
||
fn run_command_with_args<S>(command_name: S, args: &Vec<String>) | ||
where S: AsRef<std::ffi::OsStr> + Copy { | ||
where S: AsRef<std::ffi::OsStr> + Copy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is due to rustfmt? If you want to reformat code you're not changing, I'll consider that, but please do that reformatting in a separate commit.
build.rs
Outdated
panic!("{} execution failed", command_name.as_ref().to_str().unwrap()); | ||
} | ||
} | ||
|
||
fn compile(file: &str, target_info: &TargetInfo, mut out_dir: PathBuf) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that the gcc crate automatically parallelizes the build if you pass in multiple files, and so did the make
-based approach. So, we need to decide whether we want to use the gcc crate's parallelism support, or whether we're going to (perhaps in a separate PR, and perhaps not necessarily you writing it) do the parallelism ourselves.
The benefit of doing the parallelism ourselves is that we can do it for the *.pl
-> *.S
and .S
-> .o
steps too. The downside to doing the parallelism ourselves is that it is more work than relying on the gcc crate's built-in stuff.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gcc crate is not capable to distinguish between different kind of files. If I pass all RING_TEST_SRCS to the gcc crate I need to set the cpp flag. This means everything is compiled as c++ file. (The gcc crate simply calls CC or CXX on all passed files.) At this point some of the supported compilers are beginning to complain about incorrect compiler and linker flags. For example see this build.
Because of this I decided to compile every file on it's own. It should be simple to call this in parallel by using par_iter form rayon like the gcc crate.
Thinking about this more: The first step, I think, is agreeing on a plan. My main concern is whether we can (eventually) support incremental builds and parallelized builds. I'd like to hear your thoughts and make sure we agree on how that could eventually work, even if we don't do that in this PR. After that, I'd like to see the PR broken up into at least these parts:
I would also be happy if #4 could be broken into multiple parts (e.g. dealing with the perlasm stuff in a separate commit), if that isn't an unreasonable amount of work. Does this make sense to you? |
The current version already checks if a file needs to be recompiled. (See the need_run method.). If someone changes a header file everything is recompiled. I've split the commit into smaller parts. Hopefully this is now easier to review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making the changes. Here's another round of review. I didn't review everything carefully because I think there's going to be a lot of changes already.
build.rs
Outdated
|
||
fn find_msbuild_exe(program_files_env_var: &str, | ||
optional_amd64: Option<&str>) | ||
-> Result<std::ffi::OsString, ()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We never return Err(...)
here, so the return type should be removed.
build.rs
Outdated
disable_opt, | ||
&num_jobs, | ||
lib_path.clone(), | ||
out_dir)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We never return Err()
so we should remove the try!(...)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how to configure rustfmt
to format this in the compact style, but it should be like this:
build_msvc(&target_triple, disable_opt, &num_jobs, lib_path.clone(),
out_dir);
build.rs
Outdated
@@ -65,7 +65,7 @@ | |||
)] | |||
|
|||
use std::env; | |||
use std::path::Path; | |||
use std::path::{Path, PathBuf}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some uses of std::path::PathBuf
below that should have the std::path::
qualification removed.
build.rs
Outdated
let configuration = if disable_opt { "Debug" } else { "Release" }; | ||
let args = vec![ | ||
let configuration = if disable_opt { "Debug" } else { "Release" }; | ||
let args = vec![ | ||
format!("/m:{}", num_jobs), | ||
format!("/p:Platform={}", platform), | ||
format!("/p:Configuration={}", configuration), | ||
format!("/p:OutRootDir={}/", out_dir), | ||
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines are too indented. (When I reduce the indention by 4 spaces in my copy and then run rustfmt
it keeps it as-is.)
build.rs
Outdated
const LIB_NAME: &'static str = "ring"; | ||
|
||
const RING_SRC: &'static [&'static str] = &["crypto/aes/aes.c", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't figure out how to make rustfmt do something reasonable with this. Let's format all of these variables containing lists of files like RING_X86_64_SRC
and add #[cfg_attr(rustfmt, rustfmt_skip)]
to each of them.
build.rs
Outdated
"crypto/test/file_test.h", | ||
"crypto/test/bn_test_util.h"]; | ||
|
||
const RING_PERL_INCLUDES: &'static [&'static str] = &["crypto/sha/asm/sha-x86_64.pl"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
crypto/sha/asm/sha-armv8.pl
is another thing that should be added to this list.
build.rs
Outdated
"-Wnested-externs", | ||
"-Wstrict-prototypes"]; | ||
|
||
const CPP_FLAGS: &'static [&'static str] = &["-std=c++0x", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed you copied CFLAGS
and CPPFLAGS
from mk/top_of_makefile.mk, but you didn't copy CXXFLAGS
. Instead of looks like you confused CPPFLAGS
and CXXFLAGS
. CPPFLAGS
should be passed to every compilation (*.S, *.c, *.cc), CFLAGS
should additionally be passed for *.c only, and CXXFLAGS
should be passed for *.cc.
In particular, -std=c++0x
should be in CXXFLAGS
but most of the other stuff here should remain in CPPFLAGS
.
build.rs
Outdated
let test_header_change = RING_TEST_HEADERS.iter() | ||
.map(Path::new) | ||
.any(|p| need_run(&p, test_target)) || | ||
lib_header_change; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest that we just check if any of find crypto include mk -name "*.h" -o -name "*.inl" -o -name "*.mk"
changed, and if so, rebuild all the libraries. Especially since the test lib will go away sometime soon.
build.rs
Outdated
} | ||
c.compile("libring-core.a"); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please factor out the duplicate logic between the code in this function above this line and the code below this line.
build.rs
Outdated
@@ -370,6 +464,45 @@ fn run_command_with_args<S>(command_name: S, args: &Vec<String>) | |||
} | |||
} | |||
|
|||
fn make_asm(source: &str, mut dst: PathBuf, target_info: &TargetInfo) | |||
-> String { | |||
let p = Path::new(source); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we need to consider crypto/perlasm/*.pl
and crypto/sha/{sha-armv8.pl, sha-x86_64.pl}
the same way we consider *.h and *.inl in the compile()
function.
Are you the copyright holder for these changes, or is there an employer or somebody else that owns the copyright? If somebody else, who? Please add the contributor statement to the bottom of each commit; See https://github.com/briansmith/ring#contributing. If you add the contributor statement to the commit that factors out the |
1f5eadf
to
308502e
Compare
I've updated the pull request according to your comments. |
Thanks! I landed the "Move msvc build logic to own function" commit as a0ee4b5, tweaked as I suggested above. |
@weiznich Just to make sure you're aware, I also wrote many comments above that are now hidden behind the "show outdated" links. |
Coverage remained the same at 90.794% when pulling 308502e77328cd427ad7e3b02e71ae8b944a04ec on weiznich:fix_320 into b4b084e on briansmith:master. |
1 similar comment
Coverage remained the same at 90.794% when pulling 308502e77328cd427ad7e3b02e71ae8b944a04ec on weiznich:fix_320 into b4b084e on briansmith:master. |
Coverage remained the same at 90.794% when pulling 308502e77328cd427ad7e3b02e71ae8b944a04ec on weiznich:fix_320 into b4b084e on briansmith:master. |
ffab358
to
8bc2e0a
Compare
Thanks, I've missed them. The current version should address those comments. Also I added a commit which introducing parallel compilation of the native stuff. But I'm not sure if this improves the compiletime. |
Cargo.toml
Outdated
@@ -266,6 +266,11 @@ name = "ring" | |||
libc = "0.2.20" | |||
untrusted = "0.3.2" | |||
|
|||
[build-dependencies] | |||
gcc = "0.3" | |||
target_build_utils = "0.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change the target_build_dependencies dependency to { version = "0.2", default-features = false }
to reduce the dependencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I filed #457 for removing the target_build_utils dependency after this PR is merged. The target_build_utils itself is about 10 additional transitive dependencies, which is too much long-term. It's OK for now, in order to make forward progress.
Cargo.toml
Outdated
@@ -266,6 +266,11 @@ name = "ring" | |||
libc = "0.2.20" | |||
untrusted = "0.3.2" | |||
|
|||
[build-dependencies] | |||
gcc = "0.3" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use gcc = { version = "0.3", features = ["parallel"] }
because we do the parallelism ourselves, right? If that is the case, let's add a comment to that effect here.
In travis.sh, we run "make --version". That should be removed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reviewed up to, but not including, the PerlAsm changes. I'll make the iOS and macOS changes myself on top of your changes.
build.rs
Outdated
@@ -15,7 +15,7 @@ | |||
// TODO: Deny `unused_qualifications` after | |||
// https://github.com/rust-lang/rust/issues/37345 is fixed. | |||
#![allow( | |||
box_pointers, // TODO | |||
// TODO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the TODO comment.
else ifeq ($(CMAKE_BUILD_TYPE),RELEASE) | ||
CPPFLAGS += -DNDEBUG -O3 | ||
else ifeq ($(CMAKE_BUILD_TYPE),RELWITHDEBINFO) | ||
CPPFLAGS += -DNDEBUG -O3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the most serious issue so far: You didn't copy the logic for NDEBUG into the new build system. In particular, in non-debug builds, we need to add -DNDEBUG
to CPPFLAGS so that the assertions are not compiled in.
(It seems gcc-rs automatically adds -O3 or -O0 depending on whether or not --release
is passed on the command line, so you don't need to do anything with -O
, just the NDEBUG logic.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-DNDEBUG is now added if OPT_LEVEL != "0" otherwise -DDEBUG is added
build.rs
Outdated
"-Wnested-externs", | ||
"-Wstrict-prototypes"]; | ||
|
||
const CXX_FLAGS: &'static [&'static str] = &["-std=c++0x"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment: // GCC 4.6 requires "c++0x" instead of "c++11"
.
build.rs
Outdated
|
||
#[cfg_attr(rustfmt, rustfmt_skip)] | ||
const C_FLAGS: &'static [&'static str] = | ||
&["-std=c1x", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment: // GCC 4.6 requires "c1x" instead of "c11"
.
build.rs
Outdated
let _ = c.flag(f); | ||
} | ||
if target_info.target_os() != "none" { | ||
let _ = c.flag("-fstack-protector"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you confused "CPPFLAGS" and "CXXFLAGS". This should be done for both "c" and "cc". Here's the logic you need to implement:
ifneq ($(filter-out none redox,$(TARGET_SYS)),)
CPPFLAGS += -fstack-protector
endif
build.rs
Outdated
let _ = match (target_info.target_os(), | ||
target_info.target_arch()) { | ||
("macos", _) => c.flag("-gfull"), | ||
_ => c.flag("-g3"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be done for both "c" and "cc". (Again, I think you confused CXXFLAGS and CPPFLAGS.)
build.rs
Outdated
} | ||
let _ = match (target_info.target_os(), | ||
target_info.target_arch()) { | ||
("macos", _) => c.flag("-gfull"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy the comment over: // ``-gfull`` is required for Darwin's |-dead_strip|.
LDFLAGS += -Wl,--gc-sections | ||
endif | ||
|
||
ASFLAGS += -Wa,--noexecstack,-gdwarf |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ASFLAGS
logic wasn't copied over.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ASFLAGS is not copied because it seems to be not used (As far as I can tell from the output of a Makefile based build)
build.rs
Outdated
a.extend(b.into_iter()); | ||
a | ||
}); | ||
if objs.par_iter() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment here about what this does. I think it would be something like "Rebuild the library if necessary."
build.rs
Outdated
header_changed: bool) | ||
where P: ParallelIterator<Item = String> | ||
{ | ||
let objs = additional.chain(lib_src.par_iter().map(|a| String::from(*a))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a comment here, e.g. "Compile all the (dirty) source files into object files."
When you make the next set of changes, please:
In particular, if you rebase on top of the current master then the build script output will be in the Travis CI logs because I just committed a change to run |
Here's the process I'm using to review the changes related to compiler flags: First I pick an arbitrary target, e.g. 64-bit Linux. I run Then I find the command line for compiling an arbitrary C file, e.g. crypto.c, in each build log. I replace spaces with newlines, sort the lines, and then diff the two commands to see what flags are different between master and your PR. Then I find a command line for compiling an arbitrary C++ file, e.g. bn_test.cc, and do the same diffing procedure. Similarly, tomorrow I will do the same for an arbitrary perl invocation, for an arbitrary assembly invocation, and for each linking/librarian invocation. In addition to all the above, I've inspected the Makefiles, looking in particular for comments that explain important design decisions. Hopefully I've asked you to copy all the important comments in my current review comments. (There are a bunch of TODO comments that you don't need to worry about; I've captured them in a separate document.) Then I will repeat the whole procedure for 32-bit Linux. And then 64-bit macOS, then 64-bit iOS, then 32-bit iOS, then 64-bit Android, then 32-bit Android. Things have to be reviewed this way, instead of comparing the old Makefile logic to the new build.rs code, because (1) it is too hard to compare them exactly, and (2) the gcc crate adds its own additional command line parameters that aren't obvious. So, it is slow going but it is getting done. |
Oh, another thing I forgot in the previous comment: It is important not only to run |
* Fix briansmith#320 I agree to license my contributions to each file under the terms given at the top of each file I changed.
I agree to license my contributions to each file under the terms given at the top of each file I changed.
I agree to license my contributions to each file under the terms given at the top of each file I changed.
* Track all source, header and make files I agree to license my contributions to each file under the terms given at the top of each file I changed.
I agree to license my contributions to each file under the terms given at the top of each file I changed.
I've rebased everything on master and addressed the comments. I had no time to do any in depth comparison between the output of the old and the new build scripts. |
Changes Unknown when pulling 1d2939f on weiznich:fix_320 into ** on briansmith:master**. |
Still working on this. At this point there's no reason to update this PR any further. I've got a private branch that builds on this PR to get the macOS and Windows stuff working. Hopefully done in the next few days. |
Thanks very much for contributing this! I landed a modified version of this in this series of commits: 86c24b9 Use only build.rs to build the native libraries for non-Windows builds. This seems to have been the fix for the macOS build failures: 5efd2ae Pass I also extended your PR to generate more output: I also cleaned up some stuff (I actually pushed most of my cleanup stuff in commits earlier in the week): I also removed the target_build_utils dependency. It simply added too many dependencies and slowed down a clean build way too much. AFAICT all of its functionality is subsumed by recent versions of Cargo with the Finally, because Windows is the primary platform I develop ring on, it is important to use the new build system on Windows right away, so I moved Windows over as well: It's unlikely that things are perfect yet. I bet we broke some of the platforms we don't have on Travis CI like Redox (cc @jackpot51) and/or OpenBSD (cc @tatsuya6502) and/or iOS (cc @kali). My policy is to treat platforms that we don't have CI coverage for as "Tier 2" in that we don't back out changes that break them, but we accept bug fixes to get them working again, and we notify relevant people when we suspect we might have broken them. And, I still need to go through the Windows build and add back some inessential compilation flags. I'll do that in the next few days. Thanks again for the tremendous contribution here! |
Wow, nice cleanup! I can confirm the tests are passing on ios on a real phone, compiled for armv7 and aarch64. Building for the ios simulator is not workign though. I'll open a separate issue for that. |