Skip to content
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

Fix pkg-config library output for MSVC and enable Windows CI #406

Merged
merged 2 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/example-project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ jobs:
working-directory: example-project
run: |
sudo cp -r temp/usr/local/* /usr/local/

- name: Install into Cargo root
if: startsWith(matrix.os, 'windows')
shell: bash
working-directory: example-project
run: |
cargo cinstall --verbose --release --prefix=$CARGO_HOME

- name: Test pkg-config
if: startsWith(matrix.os, 'macos')
Expand All @@ -75,6 +82,28 @@ jobs:
uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: pkgconf

- name: Setup Meson + Ninja
if: startsWith(matrix.os, 'windows')
run: |
python3 -m pip install --upgrade pip setuptools wheel
python3 -m pip install meson ninja

- name: Setup MSVC for test
if: startsWith(matrix.os, 'windows')
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x86_64

# https://github.com/pkgconf/pkgconf/issues/364
- name: Install pkgconf
if: startsWith(matrix.os, 'windows')
run: |
git clone https://github.com/amyspark/pkgconf --branch msvc
cd pkgconf
meson setup build --prefix=$env:CARGO_HOME
meson compile -C build
meson install -C build

- name: Test pkgconf
if: startsWith(matrix.os, 'ubuntu')
Expand All @@ -90,6 +119,18 @@ jobs:
test "${CFLAGS%% }" = "-I/usr/local/include/example-project-0.1"
test "${LIBS%% }" = "-L/usr/local/lib/${ARCHDIR} -lexample-project"

- name: Test pkgconf
if: startsWith(matrix.os, 'windows')
shell: bash
run: |
set -x
pkgconf --version
CFLAGS=$(pkgconf --cflags example_project)
LIBS=$(pkgconf --libs example_project)

test "${CFLAGS%% }" = "-I${CARGO_HOME//\\//}/bin/../include/example-project-0.1"
test "${LIBS%% }" = "-L${CARGO_HOME//\\//}/bin/../lib -lexample-project"

- name: Update dynamic linker cache
if: startsWith(matrix.os, 'ubuntu')
run: |
Expand All @@ -101,3 +142,12 @@ jobs:
run: |
make

- name: Test usage from C (Meson)
if: startsWith(matrix.os, 'windows') && matrix.toolchain-suffix == '-msvc'
working-directory: example-project/usage-from-c
shell: pwsh
run: |
$env:PKG_CONFIG="$env:CARGO_HOME/bin/pkgconf.exe"
meson setup build
meson compile -C build
meson test -C build
7 changes: 7 additions & 0 deletions example-project/usage-from-c/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project('example', 'c')

dep = dependency('example_project', static: true, required: true)

exe = executable('run_tests', files('run_tests.c'), dependencies: dep)

test('run_tests', exe)
70 changes: 59 additions & 11 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use anyhow::Context as _;
use cargo_util::paths::{copy, create_dir_all, open, read, read_bytes, write};
use implib::def::ModuleDef;
use implib::{Flavor, ImportLibrary, MachineType};
use itertools::Itertools;
use semver::Version;

use crate::build_targets::BuildTargets;
Expand Down Expand Up @@ -998,6 +999,28 @@ fn deprecation_warnings(ws: &Workspace, args: &ArgMatches) -> anyhow::Result<()>
Ok(())
}

fn static_libraries(link_line: &str, rustc_target: &target::Target) -> String {
link_line
.trim()
.split(' ')
.filter(|s| {
if rustc_target.env == "msvc" && s.starts_with("/defaultlib") {
return false;
}
!s.is_empty()
})
.unique()
.map(|lib| {
if rustc_target.env == "msvc" && lib.ends_with(".lib") {
return format!("-l{}", lib.trim_end_matches(".lib"));
}
lib.trim().to_string()
})
.filter(|s| !s.is_empty())
.collect::<Vec<_>>()
.join(" ")
}

pub fn cbuild(
ws: &mut Workspace,
config: &GlobalContext,
Expand Down Expand Up @@ -1111,25 +1134,21 @@ pub fn cbuild(
// if the hash value does not match.
if new_build && !cpkg.finger_print.is_valid() {
let name = &cpkg.capi_config.library.name;
let static_libs = if only_cdylib {
"".to_string()
let (pkg_config_static_libs, static_libs) = if only_cdylib {
(String::new(), String::new())
} else if let Some(libs) = exec.link_line.lock().unwrap().values().next() {
(static_libraries(libs, &rustc_target), libs.to_string())
} else {
exec.link_line
.lock()
.unwrap()
.values()
.next()
.map_or("", |s| s)
.to_string()
(String::new(), String::new())
};
let capi_config = &cpkg.capi_config;
let build_targets = &cpkg.build_targets;

let mut pc = PkgConfig::from_workspace(name, &cpkg.install_paths, args, capi_config);
if only_staticlib {
pc.add_lib(&static_libs);
pc.add_lib(&pkg_config_static_libs);
}
pc.add_lib_private(&static_libs);
pc.add_lib_private(&pkg_config_static_libs);

build_pc_files(ws, &capi_config.pkg_config.filename, &root_output, &pc)?;

Expand Down Expand Up @@ -1184,6 +1203,8 @@ pub fn cbuild(
}
}

// This can be supplied to Rust, so it must be in
// linker-native syntax
cpkg.finger_print.static_libs = static_libs;
cpkg.finger_print.store()?;
} else {
Expand Down Expand Up @@ -1316,4 +1337,31 @@ mod tests {
let sover = library.sover();
assert_eq!(sover, "1.0.0");
}

#[test]
pub fn test_lib_listing() {
let libs_osx = "-lSystem -lc -lm";
let libs_linux = "-lgcc_s -lutil -lrt -lpthread -lm -ldl -lc";
let libs_msvc = "kernel32.lib advapi32.lib kernel32.lib ntdll.lib userenv.lib ws2_32.lib kernel32.lib ws2_32.lib kernel32.lib msvcrt.lib /defaultlib:msvcrt";
let libs_mingw = "-lkernel32 -ladvapi32 -lkernel32 -lntdll -luserenv -lws2_32 -lkernel32 -lws2_32 -lkernel32";

let target_osx = target::Target::new(Some("x86_64-apple-darwin"), false).unwrap();
let target_linux = target::Target::new(Some("x86_64-unknown-linux-gnu"), false).unwrap();
let target_msvc = target::Target::new(Some("x86_64-pc-windows-msvc"), false).unwrap();
let target_mingw = target::Target::new(Some("x86_64-pc-windows-gnu"), false).unwrap();

assert_eq!(static_libraries(&libs_osx, &target_osx), "-lSystem -lc -lm");
assert_eq!(
static_libraries(&libs_linux, &target_linux),
"-lgcc_s -lutil -lrt -lpthread -lm -ldl -lc"
);
assert_eq!(
static_libraries(&libs_msvc, &target_msvc),
"-lkernel32 -ladvapi32 -lntdll -luserenv -lws2_32 -lmsvcrt"
);
assert_eq!(
static_libraries(&libs_mingw, &target_mingw),
"-lkernel32 -ladvapi32 -lntdll -luserenv -lws2_32"
);
}
}