Skip to content

Commit

Permalink
Fix the need of staticlib target to have a build.rs customization
Browse files Browse the repository at this point in the history
  • Loading branch information
yvan-sraka committed Jan 17, 2023
1 parent 7af148d commit b2c64a4
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 46 deletions.
18 changes: 9 additions & 9 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
};
toolchain = (pkgs.rustChannelOf {
rustToolchain = ./rust-toolchain;
sha256 = "sha256-DzNEaW724O8/B8844tt5AVHmSjSQ3cmzlU4BP90oRlY=";
sha256 = "sha256-Zk2rxv6vwKFkTTidgjPm6gDsseVmmljVt201H7zuDkk=";
}).rust;
in {
defaultPackage = naersk'.buildPackage ./.;
Expand Down
31 changes: 24 additions & 7 deletions src/build.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
//! Support to dynamic library, require in user crate a small `build.rs` script,
//! that link to generated Rust library a filename with GHC version suffix, e.g.
//! `libNAME-ghcVERSION.so`, `libNAME-ghcVERSION.dylib` or `NAME-ghcVERSION.dll`
//!
//! Version is the one of `ghc` in `$PATH`, but could be overide with
//! `$CABAL_PACK_GHC_VERSION` env variable!
//! Support to both static and dynamic library, require in user crate a small
//! `build.rs` script.
//!
//! This build file was written with the constraint in mind of no-dependency to
//! keep user setup simple and be easily mergeable with an existing `build.rs`
//! automation!

fn main() {
// Support to static library require that library name is prefixed by `C`
// https://gitlab.haskell.org/ghc/ghc/-/issues/22564#note_469030
let path = format!("target/{}", std::env::var("PROFILE").unwrap());
#[cfg(target_family = "windows")]
let prefix = "";
#[cfg(target_family = "unix")]
let prefix = "lib";
let name = env!("CARGO_PKG_NAME");
#[cfg(target_family = "windows")]
let ext = "lib";
#[cfg(target_family = "unix")]
let ext = "a";
let source = format!("{prefix}{name}.{ext}");
let target = format!("{prefix}C{name}.{ext}");
symlink(&path, &source, &target);

// Support to dynamic library require to generated a filename with GHC
// version suffix, e.g. `libNAME-ghcVERSION.so`, `libNAME-ghcVERSION.dylib`
// or `NAME-ghcVERSION.dll`
//
// Version is the one of `ghc` in `$PATH`, but could be overide with
// `$CABAL_PACK_GHC_VERSION` env variable!
let suffix = format!(
"-ghc{}",
std::env::var("CABAL_PACK_GHC_VERSION")
Expand All @@ -39,12 +51,17 @@ fn main() {
let ext = "so";
let source = format!("{prefix}{name}.{ext}");
let target = format!("{prefix}{name}{suffix}.{ext}");
symlink(&path, &source, &target);
}

fn symlink(path: &str, source: &str, target: &str) {
if !std::path::Path::new(&format!("{path}/{target}")).exists() {
std::fs::create_dir_all(path).unwrap();
std::env::set_current_dir(path).unwrap();
std::fs::OpenOptions::new()
.create(true)
.write(true)
.open(&source)
.open(source)
.unwrap();
#[cfg(target_family = "windows")]
std::os::windows::fs::symlink_file(source, target).unwrap();
Expand Down
9 changes: 3 additions & 6 deletions src/cabal.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/// Generate user `.cabal`, taking `--enable-nix` option into account
pub(crate) fn generate(name: &str, module: &str, version: &str, enable_nix: bool) -> String {
let lib_name = name.replace('-', "_"); // When a lib is created, "-" is replaced by "_"
let package_name = name.replace('_', "-"); // cabal does not expect "_" for packages names

let build_type = if enable_nix {
"
build-type: Simple"
Expand All @@ -20,7 +17,7 @@ custom-setup
-- `haskell.nix` tell GHC linker where to find the `libNAME.a` by setting
-- automatically `extra-lib-dirs`:
-- https://input-output-hk.github.io/haskell.nix/tutorials/pkg-map.html
extra-libraries: {lib_name}
extra-libraries: {name}
-- Cross-compilation to target `x86_64-w64-mingw32-cc` thrown a lot of
-- `undefined reference to 'X'` errors during linking stage ...
Expand All @@ -35,7 +32,7 @@ custom-setup
format!(
"
-- Libraries that are bundled with the package.
extra-bundled-libraries: {lib_name}"
extra-bundled-libraries: {name}"
)
};

Expand All @@ -52,7 +49,7 @@ custom-setup
-- documentation, see: http://haskell.org/cabal/users-guide/
--
-- The name of the package.
name: {package_name}
name: {module}
-- The package version.
-- See the Haskell package versioning policy (PVP) for standards
Expand Down
7 changes: 2 additions & 5 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,13 @@ pub(crate) enum Error {
* please back up it before re-running `cargo cabal init --overwrite` command
*/
CabalFilesExist(String),
/** `build.rs` file already exist, but `crates-type = [ "cdylib" ]` target
* need to generate one, please either remove this option or back up it
* before re-running `cargo cabal init --overwrite` command
/** `build.rs` file already exist, but `cargo-cabal` need to generate one,
* please back up it before re-running `cargo cabal init --overwrite` command
*/
BuildFileExist,
/** `flake.nix` file already exist, but `--enable-nix` option need to
* generate one, please either remove this CLI arg or back up it before
* re-running `cargo cabal init --overwrite` command
*/
FlakeFileExist,
/// `{0}` is an invalid crate name, it should be prefixed by `C` like `C{0}`
InvalidCrateName(String)
}
26 changes: 8 additions & 18 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ mod errors;
mod flake;
mod hsbindgen;

use crate::cargo::{get_crate_type, CrateType};
use crate::cargo::{get_crate_type};
use ansi_term::Colour;
use clap::{arg, Parser, Subcommand};
use errors::Error;
Expand Down Expand Up @@ -373,14 +373,8 @@ fn init(
clean(name)?;
}

// Check that crate name is prefixed by `C` ...
// https://gitlab.haskell.org/ghc/ghc/-/issues/22564#note_469030
name.starts_with('C')
.then_some(())
.ok_or_else(|| Error::InvalidCrateName(name.to_owned()))?;

// Check that project have a `crate-type` target ...
let crate_type = get_crate_type(root).ok_or(Error::NoCargoLibTarget)?;
get_crate_type(root).ok_or(Error::NoCargoLibTarget)?;

// Check that `cargo cabal init` have not been already run ...
let cabal = format!("{name}.cabal");
Expand All @@ -392,11 +386,9 @@ fn init(
.then_some(())
.ok_or_else(|| Error::CabalFilesExist(name.to_owned()))?;
// ... and that no existing file would conflict ...
if crate_type == CrateType::DynLib {
(!Path::new("build.rs").exists())
.then_some(())
.ok_or(Error::BuildFileExist)?;
}
(!Path::new("build.rs").exists())
.then_some(())
.ok_or(Error::BuildFileExist)?;
if enable_nix {
(!Path::new("flake.rs").exists())
.then_some(())
Expand All @@ -414,11 +406,9 @@ fn init(
fs::write("hsbindgen.toml", hsbindgen::generate(module))
.map_err(|_| Error::FailedToWriteFile("hsbindgen.toml".to_owned()))?;

// If `crate-type = [ "cdylib" ]` then a custom `build.rs` is needed ...
if crate_type == CrateType::DynLib {
fs::write("build.rs", include_str!("build.rs"))
.map_err(|_| Error::FailedToWriteFile("build.rs".to_owned()))?;
}
// A custom `build.rs` is needed by both static and dynamic libraries targets ...
fs::write("build.rs", include_str!("build.rs"))
.map_err(|_| Error::FailedToWriteFile("build.rs".to_owned()))?;

// `--enable-nix` CLI option generate a `flake.nix` rather than a `Setup.lhs`
if enable_nix {
Expand Down

0 comments on commit b2c64a4

Please sign in to comment.