Skip to content

Commit 6fda365

Browse files
committed
Remove dependency on cmake
I've spent too many hours of my life bending over backwards trying to satisfy native libraryies' build systems. The most recent pain is that informing a native build system of its dependencies (such as telling libgit2 where libssh2 is installed) is an absolute never-ending nightmare. The towel is now thrown in as `cmake` is jettisoned and this is now just using the `cc` crate to directly compile all the various C code. For some more info see alexcrichton/curl-rust#225
1 parent 3d61c66 commit 6fda365

File tree

3 files changed

+97
-169
lines changed

3 files changed

+97
-169
lines changed

libgit2-sys/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ libz-sys = "1.0.18"
2323

2424
[build-dependencies]
2525
pkg-config = "0.3"
26-
cmake = "0.1.24"
2726
cc = "1.0"
2827

2928
[target.'cfg(unix)'.dependencies]

libgit2-sys/build.rs

Lines changed: 96 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,15 @@
1-
extern crate cmake;
21
extern crate cc;
32
extern crate pkg_config;
43

54
use std::env;
6-
use std::ffi::OsString;
7-
use std::fs::{self, File};
8-
use std::io::prelude::*;
5+
use std::fs;
96
use std::path::{Path, PathBuf};
107
use std::process::Command;
118

12-
macro_rules! t {
13-
($e:expr) => (match $e{
14-
Ok(e) => e,
15-
Err(e) => panic!("{} failed with {}", stringify!($e), e),
16-
})
17-
}
18-
199
fn main() {
2010
let https = env::var("CARGO_FEATURE_HTTPS").is_ok();
2111
let ssh = env::var("CARGO_FEATURE_SSH").is_ok();
2212
let curl = env::var("CARGO_FEATURE_CURL").is_ok();
23-
if ssh {
24-
register_dep("SSH2");
25-
}
26-
if https {
27-
register_dep("OPENSSL");
28-
}
29-
if curl {
30-
register_dep("CURL");
31-
}
32-
let has_pkgconfig = Command::new("pkg-config").output().is_ok();
3313

3414
if env::var("LIBGIT2_SYS_USE_PKG_CONFIG").is_ok() {
3515
if pkg_config::find_library("libgit2").is_ok() {
@@ -43,188 +23,137 @@ fn main() {
4323
}
4424

4525
let target = env::var("TARGET").unwrap();
46-
let host = env::var("HOST").unwrap();
4726
let windows = target.contains("windows");
48-
let msvc = target.contains("msvc");
49-
let mut cfg = cmake::Config::new("libgit2");
50-
51-
#[cfg(feature = "ssh_key_from_memory")]
52-
cfg.define("GIT_SSH_MEMORY_CREDENTIALS", "1");
53-
54-
if msvc {
55-
// libgit2 passes the /GL flag to enable whole program optimization, but
56-
// this requires that the /LTCG flag is passed to the linker later on,
57-
// and currently the compiler does not do that, so we disable whole
58-
// program optimization entirely.
59-
cfg.cflag("/GL-");
60-
61-
// Currently liblibc links to msvcrt which apparently is a dynamic CRT,
62-
// so we need to turn this off to get it to link right.
63-
let features = env::var("CARGO_CFG_TARGET_FEATURE")
64-
.unwrap_or(String::new());
65-
if features.contains("crt-static") {
66-
cfg.define("STATIC_CRT", "ON");
67-
} else {
68-
cfg.define("STATIC_CRT", "OFF");
69-
}
27+
let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
28+
let include = dst.join("include");
29+
let mut cfg = cc::Build::new();
30+
31+
// Copy over all header files
32+
cp_r("libgit2/include".as_ref(), &include);
33+
34+
cfg.include(&include)
35+
.include("libgit2/src")
36+
.out_dir(dst.join("build"))
37+
.warnings(false);
38+
39+
// Include all cross-platform C files
40+
add_c_files(&mut cfg, "libgit2/src".as_ref());
41+
add_c_files(&mut cfg, "libgit2/src/xdiff".as_ref());
42+
43+
// These are activated by feautres, but they're all unconditionally always
44+
// compiled apparently and have internal #define's to make sure they're
45+
// compiled correctly.
46+
add_c_files(&mut cfg, "libgit2/src/transports".as_ref());
47+
add_c_files(&mut cfg, "libgit2/src/streams".as_ref());
48+
49+
// Always use bundled http-parser for now
50+
cfg.include("libgit2/deps/http-parser")
51+
.file("libgit2/deps/http-parser/http_parser.c");
52+
53+
if windows {
54+
add_c_files(&mut cfg, "libgit2/src/win32".as_ref());
55+
} else {
56+
add_c_files(&mut cfg, "libgit2/src/unix".as_ref());
7057
}
7158

72-
// libgit2 uses pkg-config to discover libssh2, but this doesn't work on
73-
// windows as libssh2 doesn't come with a libssh2.pc file in that install
74-
// (or when pkg-config isn't found). As a result we just manually turn on
75-
// SSH support in libgit2 (a little jankily) here...
76-
let mut ssh_forced = false;
77-
if ssh && (windows || !has_pkgconfig) {
78-
if let Ok(libssh2_include) = env::var("DEP_SSH2_INCLUDE") {
79-
ssh_forced = true;
80-
if msvc {
81-
cfg.cflag(format!("/I{}", libssh2_include))
82-
.cflag("/DGIT_SSH");
83-
} else {
84-
cfg.cflag(format!("-I{}", sanitize_sh(libssh2_include.as_ref())))
85-
.cflag("-DGIT_SSH");
86-
}
87-
}
88-
}
59+
let mut features = String::new();
8960

90-
// When cross-compiling, we're pretty unlikely to find a `dlltool` binary
91-
// lying around, so try to find another if it exists
92-
if windows && !host.contains("windows") {
93-
let c_compiler = cc::Build::new().cargo_metadata(false)
94-
.get_compiler();
95-
let exe = c_compiler.path();
96-
let path = env::var_os("PATH").unwrap_or(OsString::new());
97-
let exe = env::split_paths(&path)
98-
.map(|p| p.join(&exe))
99-
.find(|p| p.exists());
100-
if let Some(exe) = exe {
101-
if let Some(name) = exe.file_name().and_then(|e| e.to_str()) {
102-
let name = name.replace("gcc", "dlltool");
103-
let dlltool = exe.with_file_name(name);
104-
cfg.define("DLLTOOL", &dlltool);
105-
}
106-
}
61+
features.push_str("#ifndef INCLUDE_features_h\n");
62+
features.push_str("#define INCLUDE_features_h\n");
63+
features.push_str("#define GIT_THREADS 1\n");
64+
features.push_str("#define GIT_USE_NSEC 1\n");
65+
features.push_str("#define GIT_USE_STAT_MTIM 1\n");
66+
if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "32" {
67+
features.push_str("#define GIT_ARCH_32 1\n");
68+
} else {
69+
features.push_str("#define GIT_ARCH_64 1\n");
10770
}
10871

10972
if ssh {
110-
cfg.register_dep("SSH2");
111-
} else {
112-
cfg.define("USE_SSH", "OFF");
73+
if let Some(path) = env::var_os("DEP_SSH2_INCLUDE") {
74+
cfg.include(path);
75+
}
76+
features.push_str("#define GIT_SSH 1\n");
77+
features.push_str("#define GIT_SSH_MEMORY_CREDENTIALS 1\n");
11378
}
11479
if https {
115-
cfg.register_dep("OPENSSL");
116-
} else {
117-
cfg.define("USE_OPENSSL", "OFF");
118-
cfg.define("USE_HTTPS", "OFF");
80+
features.push_str("#define GIT_HTTPS 1\n");
81+
82+
if windows {
83+
features.push_str("#define GIT_WINHTTP 1\n");
84+
features.push_str("#define GIT_SHA1_WIN32 1\n");
85+
cfg.file("libgit2/src/hash/hash_win32.c");
86+
} else if target.contains("apple") {
87+
features.push_str("#define GIT_SECURE_TRANSPORT 1\n");
88+
features.push_str("#define GIT_SHA1_COMMON_CRYPTO 1\n");
89+
cfg.file("libgit2/src/hash/hash_common_crypto.c");
90+
} else {
91+
features.push_str("#define GIT_OPENSSL 1\n");
92+
features.push_str("#define GIT_SHA1_OPENSSL 1\n");
93+
if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") {
94+
cfg.include(path);
95+
}
96+
}
11997
}
12098
if curl {
121-
cfg.register_dep("CURL");
122-
} else {
123-
cfg.define("CURL", "OFF");
99+
features.push_str("#define GIT_CURL 1\n");
100+
if let Some(path) = env::var_os("DEP_CURL_INCLUDE") {
101+
cfg.include(path);
102+
}
124103
}
125-
126-
//Use bundled http-parser if cross compiling
127-
if host != target {
128-
cfg.define("USE_EXT_HTTP_PARSER", "OFF");
104+
if let Some(path) = env::var_os("DEP_Z_INCLUDE") {
105+
cfg.include(path);
129106
}
130107

131-
let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
132-
t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));
133-
134-
// Unset DESTDIR or libgit2.a ends up in it and cargo can't find it
135-
env::remove_var("DESTDIR");
136-
let dst = cfg.define("BUILD_SHARED_LIBS", "OFF")
137-
.define("BUILD_CLAR", "OFF")
138-
.register_dep("Z")
139-
.build();
140-
141-
// Make sure libssh2 was detected on unix systems, because it definitely
142-
// should have been!
143-
if ssh && !ssh_forced {
144-
let flags = dst.join("build/src/git2/sys/features.h");
145-
let mut contents = String::new();
146-
t!(t!(File::open(flags)).read_to_string(&mut contents));
147-
if !contents.contains("#define GIT_SSH 1") {
148-
panic!("libgit2 failed to find libssh2, and SSH support is required");
149-
}
108+
if target.contains("apple") {
109+
features.push_str("#define GIT_USE_ICONV 1\n");
150110
}
151111

152-
// libgit2 requires the http_parser library for the HTTP transport to be
153-
// implemented, and it will attempt to use the system http_parser if it's
154-
// available. Detect this situation and report using the system http parser
155-
// the same way in this situation.
156-
//
157-
// Note that other dependencies of libgit2 like openssl, libz, and libssh2
158-
// are tracked via crates instead of this. Ideally this should be a crate as
159-
// well.
160-
let pkgconfig_file = dst.join("lib/pkgconfig/libgit2.pc");
161-
if let Ok(mut f) = File::open(&pkgconfig_file) {
162-
let mut contents = String::new();
163-
t!(f.read_to_string(&mut contents));
164-
if contents.contains("-lhttp_parser") {
165-
println!("cargo:rustc-link-lib=http_parser");
166-
}
167-
}
112+
features.push_str("#endif\n");
113+
fs::write(include.join("git2/sys/features.h"), features).unwrap();
114+
115+
cfg.compile("git2");
116+
117+
println!("cargo:root={}", dst.display());
168118

169119
if target.contains("windows") {
170120
println!("cargo:rustc-link-lib=winhttp");
171121
println!("cargo:rustc-link-lib=rpcrt4");
172122
println!("cargo:rustc-link-lib=ole32");
173123
println!("cargo:rustc-link-lib=crypt32");
174-
println!("cargo:rustc-link-lib=static=git2");
175-
println!("cargo:rustc-link-search=native={}/lib", dst.display());
176124
return
177125
}
178126

179-
println!("cargo:rustc-link-lib=static=git2");
180-
println!("cargo:rustc-link-search=native={}", dst.join("lib").display());
181127
if target.contains("apple") {
182128
println!("cargo:rustc-link-lib=iconv");
183129
println!("cargo:rustc-link-lib=framework=Security");
184130
println!("cargo:rustc-link-lib=framework=CoreFoundation");
185131
}
186132
}
187133

188-
fn register_dep(dep: &str) {
189-
if let Some(s) = env::var_os(&format!("DEP_{}_ROOT", dep)) {
190-
if !cfg!(target_env = "msvc") {
191-
prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
192-
}
193-
return
194-
}
195-
if let Some(s) = env::var_os(&format!("DEP_{}_INCLUDE", dep)) {
196-
let root = Path::new(&s).parent().unwrap();
197-
env::set_var(&format!("DEP_{}_ROOT", dep), root);
198-
let path = root.join("lib/pkgconfig");
199-
if path.exists() {
200-
if !cfg!(target_env = "msvc") {
201-
prepend("PKG_CONFIG_PATH", path);
202-
}
203-
return
134+
fn cp_r(from: &Path, to: &Path) {
135+
for e in from.read_dir().unwrap() {
136+
let e = e.unwrap();
137+
let from = e.path();
138+
let to = to.join(e.file_name());
139+
if e.file_type().unwrap().is_dir() {
140+
fs::create_dir_all(&to).unwrap();
141+
cp_r(&from, &to);
142+
} else {
143+
println!("{} => {}", from.display(), to.display());
144+
fs::copy(&from, &to).unwrap();
204145
}
205146
}
206147
}
207148

208-
fn prepend(var: &str, val: PathBuf) {
209-
let prefix = env::var(var).unwrap_or(String::new());
210-
let mut v = vec![val];
211-
v.extend(env::split_paths(&prefix));
212-
env::set_var(var, &env::join_paths(v).unwrap());
213-
}
214-
215-
fn sanitize_sh(path: &Path) -> String {
216-
let path = path.to_str().unwrap().replace("\\", "/");
217-
return change_drive(&path).unwrap_or(path);
218-
219-
fn change_drive(s: &str) -> Option<String> {
220-
let mut ch = s.chars();
221-
let drive = ch.next().unwrap_or('C');
222-
if ch.next() != Some(':') {
223-
return None
224-
}
225-
if ch.next() != Some('/') {
226-
return None
149+
fn add_c_files(build: &mut cc::Build, path: &Path) {
150+
for e in path.read_dir().unwrap() {
151+
let e = e.unwrap();
152+
let path = e.path();
153+
if e.file_type().unwrap().is_dir() {
154+
// skip dirs for now
155+
} else if path.extension().and_then(|s| s.to_str()) == Some("c") {
156+
build.file(&path);
227157
}
228-
Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
229158
}
230159
}

systest/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ authors = ["Alex Crichton <[email protected]>"]
55
build = "build.rs"
66

77
[dependencies]
8-
libgit2-sys = { path = "../libgit2-sys" }
8+
libgit2-sys = { path = "../libgit2-sys", features = ['curl', 'https', 'ssh'] }
99
libc = "0.2"
1010

1111
[build-dependencies]

0 commit comments

Comments
 (0)