Skip to content

Commit

Permalink
Merge pull request #14 from scipopt/from-source
Browse files Browse the repository at this point in the history
Fetch and compile the SCIPOptSuite from source
  • Loading branch information
mmghannam authored Mar 30, 2024
2 parents 7e6323c + fc10bf1 commit cfda74a
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 118 deletions.
39 changes: 37 additions & 2 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,42 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Test
- name: Test bundled
run: |
cargo b --features bundled -vv
cargo t --features bundled create
cargo t --features bundled --examples
cargo t --features bundled --examples
from-source-test:
strategy:
matrix:
os: [
macos-latest,
macos-14,
ubuntu-latest,
]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Install bison
if: ${{ matrix.os == 'macos-latest' || matrix.os == 'macos-14' }}
run: |
brew install bison
- name: Test from-source
run: |
cargo b --features from-source -vv
cargo t --features from-source create
cargo t --features from-source --examples
# TODO: fix this, needs tbb
# windows-from-source:
# runs-on: windows-latest
# steps:
# - uses: actions/checkout@v3
#
# - name: Test from-source
# run: |
# echo "${{ runner.workspace }}/vcpkg" >> $GITHUB_PATH
# cargo b --features from-source -vv
# cargo t --features from-source create
# cargo t --features from-source --examples
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ links = "scip"

[features]
bundled = ["reqwest", "zip", "tempfile", "zip-extract"]
from-source = ["reqwest", "zip", "tempfile", "zip-extract", "cmake"]

[build-dependencies]
bindgen = "0.64"
cc = "1.0.73"
glob = "0.3.1"
# dependencies for the static feature
reqwest = { version = "0.11", features = ["blocking", "json"], optional = true }
zip = { version = "0.5", optional = true }
tempfile = { version = "3.2", optional = true }
zip-extract = { version = "0.1.3", optional = true }
cmake = { version = "0.1.50", optional = true }

[dependencies]
cmake = "0.1.50"
163 changes: 48 additions & 115 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
mod bundled;
mod from_source;

#[cfg(any(feature = "bundled", feature = "from-source"))]
mod download;

extern crate bindgen;

use glob::glob;
use std::env;
use std::error::Error;
use std::path::PathBuf;

#[cfg(feature = "bundled")]
use tempfile::tempdir;
#[cfg(feature = "bundled")]
use std::fs::File;
#[cfg(feature = "bundled")]
use std::io::Cursor;
#[cfg(feature = "bundled")]
use std::io::Write;
#[cfg(feature = "bundled")]
use std::path::Path;


#[cfg(feature = "bundled")]
pub fn is_bundled_feature_enabled() -> bool {
true
}
use bundled::*;
use crate::from_source::{download_scip_source, is_from_source_feature_enabled, compile_scip};

#[cfg(not(feature = "bundled"))]
pub fn is_bundled_feature_enabled() -> bool {
Expand All @@ -36,10 +28,9 @@ fn _build_from_scip_dir(path: &str) -> bindgen::Builder {
println!("cargo:rustc-link-search={}", lib_dir_path);

#[cfg(windows)]
let lib_dir_path = PathBuf::from(&path).join("bin");
let lib_dir_path = PathBuf::from(&path).join("bin");
#[cfg(windows)]
println!("cargo:rustc-link-search={}", lib_dir_path.to_str().unwrap());

} else {
panic!(
"{}",
Expand Down Expand Up @@ -98,44 +89,49 @@ fn look_in_scipoptdir_and_conda_env() -> Option<bindgen::Builder> {
}
}

return None
return None;
}

fn main() -> Result<(), Box<dyn Error>> {
let builder =
if is_bundled_feature_enabled() {
download_scip();
let path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("scip_install");
_build_from_scip_dir(path.to_str().unwrap())
} else {
let builder = look_in_scipoptdir_and_conda_env();
if builder.is_some() {
builder.unwrap()
if is_bundled_feature_enabled() {
download_scip();
let path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("scip_install");
_build_from_scip_dir(path.to_str().unwrap())
} else if is_from_source_feature_enabled() {
let source_path = download_scip_source();
let build_path = compile_scip(source_path);
_build_from_scip_dir(build_path.to_str().unwrap())
} else {
println!("cargo:warning=SCIP was not found in SCIPOPTDIR or in Conda environemnt");
println!("cargo:warning=Looking for SCIP in system libraries");

let headers_dir_path = "headers/";
let headers_dir = PathBuf::from(headers_dir_path);
let scip_header_file = PathBuf::from(&headers_dir)
.join("scip")
.join("scip.h")
.to_str()
.unwrap()
.to_owned();
let scipdefplugins_header_file = PathBuf::from(&headers_dir)
.join("scip")
.join("scipdefplugins.h")
.to_str()
.unwrap()
.to_owned();

bindgen::Builder::default()
.header(scip_header_file)
.header(scipdefplugins_header_file)
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.clang_arg(format!("-I{}", headers_dir_path))
}
};
let builder = look_in_scipoptdir_and_conda_env();
if builder.is_some() {
builder.unwrap()
} else {
println!("cargo:warning=SCIP was not found in SCIPOPTDIR or in Conda environemnt");
println!("cargo:warning=Looking for SCIP in system libraries");

let headers_dir_path = "headers/";
let headers_dir = PathBuf::from(headers_dir_path);
let scip_header_file = PathBuf::from(&headers_dir)
.join("scip")
.join("scip.h")
.to_str()
.unwrap()
.to_owned();
let scipdefplugins_header_file = PathBuf::from(&headers_dir)
.join("scip")
.join("scipdefplugins.h")
.to_str()
.unwrap()
.to_owned();

bindgen::Builder::default()
.header(scip_header_file)
.header(scipdefplugins_header_file)
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.clang_arg(format!("-I{}", headers_dir_path))
}
};

#[cfg(windows)]
println!("cargo:rustc-link-lib=libscip");
Expand All @@ -156,66 +152,3 @@ fn main() -> Result<(), Box<dyn Error>> {

Ok(())
}

#[cfg(feature = "bundled")]
fn download_scip() {
let extract_path = PathBuf::from(env::var("OUT_DIR").unwrap());

if extract_path.join("scip_install").exists() {
println!("cargo:warning=SCIP was previously downloaded, skipping download");
return;
}

let os = env::consts::OS;
let arch = std::env::consts::ARCH;
println!("cargo:warning=Detected OS: {}", os);
println!("cargo:warning=Detected arch: {}", arch);

let os_string = if os == "linux" && arch == "x86_64" {
"linux"
} else if os == "macos" && arch == "x86_64" {
"macos"
} else if os == "macos" && arch == "aarch64" {
"macos-arm"
} else if os == "windows" && arch == "x86_64" {
"windows"
} else {
panic!("Unsupported OS-arch combination: {}-{}", os, arch);
};

let url = format!(
"https://github.com/scipopt/scip-sys/releases/download/v0.1.9/libscip-{os_string}.zip"
);

download_and_extract_zip(&url, &extract_path).unwrap_or_else(
|e| panic!("Failed to download and extract SCIP: {}", e),
);
}


#[cfg(not(feature = "bundled"))]
fn download_scip() {}


#[cfg(feature = "bundled")]
fn download_and_extract_zip(url: &str, extract_path: &Path) -> Result<(), Box<dyn Error>> {
// Download the ZIP file
println!("cargo:warning=Downloading from {}", url);
let response = reqwest::blocking::Client::new().get(url).send()?;
let content = response.bytes()?;

// Create a temporary file to store the ZIP
let dir = tempdir()?;
let zip_path = dir.path().join("scip.zip");
let mut temp_file = File::create(&zip_path)?;
temp_file.write_all(&content)?;
let target_dir = PathBuf::from(extract_path);

println!("cargo:warning=Downloaded to {:?}", zip_path);
println!("cargo:warning=Extracting to {:?}", target_dir);
zip_extract::extract(Cursor::new(
std::fs::read(zip_path).unwrap(),
), &target_dir, false)?;

Ok(())
}
52 changes: 52 additions & 0 deletions bundled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#[cfg(feature = "bundled")]
use std::env;
#[cfg(feature = "bundled")]
use std::path::PathBuf;
#[cfg(feature = "bundled")]
use crate::download::download_and_extract_zip;

#[cfg(feature = "bundled")]
pub fn is_bundled_feature_enabled() -> bool {
true
}


#[cfg(feature = "bundled")]
pub fn download_scip() {
let extract_path = PathBuf::from(env::var("OUT_DIR").unwrap());

if extract_path.join("scip_install").exists() {
println!("cargo:warning=SCIP was previously downloaded, skipping download");
return;
}

let os = env::consts::OS;
let arch = std::env::consts::ARCH;
println!("cargo:warning=Detected OS: {}", os);
println!("cargo:warning=Detected arch: {}", arch);

let os_string = if os == "linux" && arch == "x86_64" {
"linux"
} else if os == "macos" && arch == "x86_64" {
"macos"
} else if os == "macos" && arch == "aarch64" {
"macos-arm"
} else if os == "windows" && arch == "x86_64" {
"windows"
} else {
panic!("Unsupported OS-arch combination: {}-{}", os, arch);
};

let url = format!(
"https://github.com/scipopt/scip-sys/releases/download/v0.1.9/libscip-{os_string}.zip"
);

download_and_extract_zip(&url, &extract_path).unwrap_or_else(
|e| panic!("Failed to download and extract SCIP: {}", e),
);
}


#[cfg(not(feature = "bundled"))]
pub fn download_scip() {}

34 changes: 34 additions & 0 deletions download.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::error::Error;
use tempfile::tempdir;
use std::fs::File;
use std::io::Cursor;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use zip_extract::extract;


pub fn download_and_extract_zip(url: &str, extract_path: &Path) -> Result<(), Box<dyn Error>> {
// Download the ZIP file
println!("cargo:warning=Downloading from {}", url);
let response = reqwest::blocking::Client::new().get(url).send()?;
let content = response.bytes()?;

// Create a temporary file to store the ZIP
let dir = tempdir()?;
let zip_path = dir.path().join("scip.zip");



let mut temp_file = File::create(&zip_path)?;
temp_file.write_all(&content)?;
let target_dir = PathBuf::from(extract_path);

println!("cargo:warning=Downloaded to {:?}", zip_path);
println!("cargo:warning=Extracting to {:?}", target_dir);
extract(Cursor::new(
std::fs::read(zip_path).unwrap(),
), &target_dir, false)?;

Ok(())
}
Loading

0 comments on commit cfda74a

Please sign in to comment.