Skip to content

Commit dcc2df6

Browse files
authored
Add version_suffix_components setting (#352)
1 parent 54774e0 commit dcc2df6

File tree

6 files changed

+117
-24
lines changed

6 files changed

+117
-24
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ version = "1.2.3"
135135
install_subdir = "gstreamer-1.0"
136136
# Used to disable versioning links when installing the dynamic library
137137
versioning = false
138+
# Instead of using semver, select a fixed number of version components for your SONAME version suffix:
139+
# Setting this to 1 with a version of 0.0.0 allows a suffix of `.so.0`
140+
# Setting this to 3 always includes the full version in the SONAME (indicate any update is ABI breaking)
141+
#version_suffix_components = 2
138142
# Add `-Cpanic=abort` to the RUSTFLAGS automatically, it may be useful in case
139143
# something might panic in the crates used by the library.
140144
rustflags = "-Cpanic=abort"

src/build.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use cargo::util::command_prelude::{ArgMatches, ArgMatchesExt, CompileMode, Profi
1414
use cargo::util::interning::InternedString;
1515
use cargo::{CliResult, Config};
1616

17+
use anyhow::Context as _;
1718
use cargo_util::paths::{copy, create, create_dir_all, open, read, read_bytes, write};
1819
use semver::Version;
1920

@@ -400,16 +401,43 @@ pub struct PkgConfigCApiConfig {
400401
pub strip_include_path_components: usize,
401402
}
402403

404+
#[derive(Debug)]
405+
pub enum VersionSuffix {
406+
Major,
407+
MajorMinor,
408+
MajorMinorPatch,
409+
}
410+
403411
#[derive(Debug)]
404412
pub struct LibraryCApiConfig {
405413
pub name: String,
406414
pub version: Version,
407415
pub install_subdir: Option<String>,
408416
pub versioning: bool,
417+
pub version_suffix_components: Option<VersionSuffix>,
409418
pub import_library: bool,
410419
pub rustflags: Vec<String>,
411420
}
412421

422+
impl LibraryCApiConfig {
423+
pub fn sover(&self) -> String {
424+
let major = self.version.major;
425+
let minor = self.version.minor;
426+
let patch = self.version.patch;
427+
428+
match self.version_suffix_components {
429+
None => match (major, minor, patch) {
430+
(0, 0, patch) => format!("0.0.{patch}"),
431+
(0, minor, _) => format!("0.{minor}"),
432+
(major, _, _) => format!("{major}"),
433+
},
434+
Some(VersionSuffix::Major) => format!("{major}"),
435+
Some(VersionSuffix::MajorMinor) => format!("{major}.{minor}"),
436+
Some(VersionSuffix::MajorMinorPatch) => format!("{major}.{minor}.{patch}"),
437+
}
438+
}
439+
}
440+
413441
#[derive(Debug, Default)]
414442
pub struct InstallCApiConfig {
415443
pub include: Vec<InstallTarget>,
@@ -619,6 +647,7 @@ fn load_manifest_capi_config(pkg: &Package) -> anyhow::Result<CApiConfig> {
619647
let mut version = pkg.version().clone();
620648
let mut install_subdir = None;
621649
let mut versioning = true;
650+
let mut version_suffix_components = None;
622651
let mut import_library = true;
623652
let mut rustflags = Vec::new();
624653

@@ -636,6 +665,19 @@ fn load_manifest_capi_config(pkg: &Package) -> anyhow::Result<CApiConfig> {
636665
.get("versioning")
637666
.and_then(|v| v.as_bool())
638667
.unwrap_or(true);
668+
669+
if let Some(value) = library.get("version_suffix_components") {
670+
let value = value.as_integer().with_context(|| {
671+
format!("Value for `version_suffix_components` is not an integer: {value:?}")
672+
})?;
673+
version_suffix_components = Some(match value {
674+
1 => VersionSuffix::Major,
675+
2 => VersionSuffix::MajorMinor,
676+
3 => VersionSuffix::MajorMinorPatch,
677+
_ => anyhow::bail!("Out of range value for version suffix components: {value}"),
678+
});
679+
}
680+
639681
import_library = library
640682
.get("import_library")
641683
.and_then(|v| v.as_bool())
@@ -655,6 +697,7 @@ fn load_manifest_capi_config(pkg: &Package) -> anyhow::Result<CApiConfig> {
655697
version,
656698
install_subdir,
657699
versioning,
700+
version_suffix_components,
658701
import_library,
659702
rustflags,
660703
};
@@ -1246,3 +1289,66 @@ pub fn ctest(
12461289

12471290
ops::run_tests(ws, &ops, &test_args)
12481291
}
1292+
1293+
#[cfg(test)]
1294+
mod tests {
1295+
use super::*;
1296+
use semver::Version;
1297+
1298+
fn make_test_library_config(version: &str) -> LibraryCApiConfig {
1299+
LibraryCApiConfig {
1300+
name: "example".to_string(),
1301+
version: Version::parse(version).unwrap(),
1302+
install_subdir: None,
1303+
versioning: true,
1304+
version_suffix_components: None,
1305+
import_library: true,
1306+
rustflags: vec![],
1307+
}
1308+
}
1309+
1310+
#[test]
1311+
pub fn test_semver_zero_zero_zero() {
1312+
let library = make_test_library_config("0.0.0");
1313+
let sover = library.sover();
1314+
assert_eq!(sover, "0.0.0");
1315+
}
1316+
1317+
#[test]
1318+
pub fn test_semver_zero_one_zero() {
1319+
let library = make_test_library_config("0.1.0");
1320+
let sover = library.sover();
1321+
assert_eq!(sover, "0.1");
1322+
}
1323+
1324+
#[test]
1325+
pub fn test_semver_one_zero_zero() {
1326+
let library = make_test_library_config("1.0.0");
1327+
let sover = library.sover();
1328+
assert_eq!(sover, "1");
1329+
}
1330+
1331+
#[test]
1332+
pub fn text_one_fixed_zero_zero_zero() {
1333+
let mut library = make_test_library_config("0.0.0");
1334+
library.version_suffix_components = Some(VersionSuffix::Major);
1335+
let sover = library.sover();
1336+
assert_eq!(sover, "0");
1337+
}
1338+
1339+
#[test]
1340+
pub fn text_two_fixed_one_zero_zero() {
1341+
let mut library = make_test_library_config("1.0.0");
1342+
library.version_suffix_components = Some(VersionSuffix::MajorMinor);
1343+
let sover = library.sover();
1344+
assert_eq!(sover, "1.0");
1345+
}
1346+
1347+
#[test]
1348+
pub fn text_three_fixed_one_zero_zero() {
1349+
let mut library = make_test_library_config("1.0.0");
1350+
library.version_suffix_components = Some(VersionSuffix::MajorMinorPatch);
1351+
let sover = library.sover();
1352+
assert_eq!(sover, "1.0.0");
1353+
}
1354+
}

src/install.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ use std::path::{Component, Path, PathBuf};
33

44
use cargo::core::Workspace;
55
use cargo_util::paths::{copy, create_dir_all};
6-
use semver::Version;
76

87
use crate::build::*;
98
use crate::build_targets::BuildTargets;
10-
use crate::VersionExt;
119

1210
fn append_to_destdir(destdir: Option<&Path>, path: &Path) -> PathBuf {
1311
if let Some(destdir) = destdir {
@@ -107,8 +105,10 @@ pub(crate) struct UnixLibNames {
107105
}
108106

109107
impl UnixLibNames {
110-
pub(crate) fn new(lib_type: LibType, lib_name: &str, lib_version: &Version) -> Option<Self> {
111-
let main_version = lib_version.main_version();
108+
pub(crate) fn new(lib_type: LibType, library: &LibraryCApiConfig) -> Option<Self> {
109+
let lib_name = &library.name;
110+
let lib_version = &library.version;
111+
let main_version = library.sover();
112112

113113
match lib_type {
114114
LibType::So => {
@@ -236,12 +236,10 @@ pub fn cinstall(ws: &Workspace, packages: &[CPackage]) -> anyhow::Result<()> {
236236
if let Some(ref shared_lib) = build_targets.shared_lib {
237237
ws.config().shell().status("Installing", "shared library")?;
238238

239-
let lib_name = &capi_config.library.name;
240239
let lib_type = LibType::from_build_targets(build_targets);
241240
match lib_type {
242241
LibType::So | LibType::Dylib => {
243-
let lib = UnixLibNames::new(lib_type, lib_name, &capi_config.library.version)
244-
.unwrap();
242+
let lib = UnixLibNames::new(lib_type, &capi_config.library).unwrap();
245243
lib.install(capi_config, shared_lib, &install_path_lib)?;
246244
}
247245
LibType::Windows => {

src/lib.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,3 @@ pub mod config;
55
pub mod install;
66
pub mod pkg_config_gen;
77
pub mod target;
8-
9-
trait VersionExt {
10-
/// build the main version string
11-
fn main_version(&self) -> String;
12-
}
13-
14-
impl VersionExt for semver::Version {
15-
fn main_version(&self) -> String {
16-
match (self.major, self.minor, self.patch) {
17-
(0, 0, patch) => format!("0.0.{patch}"),
18-
(0, minor, _) => format!("0.{minor}"),
19-
(major, _, _) => format!("{major}"),
20-
}
21-
}
22-
}

src/pkg_config_gen.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ mod test {
298298
version: Version::parse("0.1.0").unwrap(),
299299
install_subdir: None,
300300
versioning: true,
301+
version_suffix_components: None,
301302
import_library: true,
302303
rustflags: Vec::default(),
303304
},

src/target.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::path::Path;
33
use anyhow::*;
44

55
use crate::build::CApiConfig;
6-
use crate::VersionExt;
76

87
/// Split a target string to its components
98
///
@@ -70,7 +69,7 @@ impl Target {
7069
let os = &self.os;
7170
let env = &self.env;
7271

73-
let sover = version.main_version();
72+
let sover = capi_config.library.sover();
7473

7574
if os == "android" {
7675
lines.push(format!("-Wl,-soname,lib{lib_name}.so"));

0 commit comments

Comments
 (0)