Skip to content

Commit efe8df0

Browse files
committed
Rename PyInit syms to avoid clashes
Built extensions in packages often have common names like speedups, utils, _objects, cpython, etc. which reside inside the package namespace. The compiled extensions each have a PyInit_<module> which needs to be renamed to PyInit_<pkg>_<module> to avoid clashes when combined into a static binary. Fixes #169
1 parent 35a7035 commit efe8df0

2 files changed

Lines changed: 103 additions & 4 deletions

File tree

pyoxidizer/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ hex = "0.3"
3636
itertools = "0.8"
3737
lazy_static = "1.3"
3838
libc = "0.2"
39+
object = { version = "0.15.0", features = ["read", "std", "write"] }
3940
regex = "1"
4041
reqwest = "0.9"
4142
rustc_version = "0.2"

pyoxidizer/src/pyrepackager/repackage.rs

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use byteorder::{LittleEndian, WriteBytesExt};
66
use glob::glob as findglob;
77
use itertools::Itertools;
88
use lazy_static::lazy_static;
9+
use object::{write, Object, ObjectSection, RelocationTarget, SectionKind, SymbolKind};
910
use slog::{info, warn};
10-
use std::collections::{BTreeMap, BTreeSet};
11+
use std::collections::{BTreeMap, BTreeSet, HashMap};
1112
use std::env;
1213
use std::fs;
1314
use std::fs::create_dir_all;
@@ -1126,7 +1127,7 @@ fn make_config_c(
11261127
}
11271128

11281129
for em in built_extension_modules.values() {
1129-
lines.push(format!("extern PyObject* {}(void);", em.init_fn));
1130+
lines.push(format!("extern PyObject* PyInit_{}(void);", em.name.replace(".", "_")));
11301131
}
11311132

11321133
lines.push(String::from("struct _inittab _PyImport_Inittab[] = {"));
@@ -1142,7 +1143,7 @@ fn make_config_c(
11421143
}
11431144

11441145
for em in built_extension_modules.values() {
1145-
lines.push(format!("{{\"{}\", {}}},", em.name, em.init_fn));
1146+
lines.push(format!("{{\"{}\", PyInit_{}}},", em.name, em.name.replace(".", "_")));
11461147
}
11471148

11481149
lines.push(String::from("{0, 0}"));
@@ -1151,6 +1152,101 @@ fn make_config_c(
11511152
lines.join("\n")
11521153
}
11531154

1155+
/// Rename object syn PyInit_foo to PyInit_<full_name> to avoid clashes
1156+
fn rename_init (
1157+
name: &String,
1158+
object_data: &[u8]
1159+
) -> Vec<u8> {
1160+
let in_object = match object::File::parse(object_data) {
1161+
Ok(object) => object,
1162+
Err(err) => {
1163+
panic!("Failed to parse compiled object for {}: {}", name, err);
1164+
}
1165+
};
1166+
1167+
let mut out_object = write::Object::new(in_object.format(), in_object.architecture());
1168+
out_object.mangling = write::Mangling::None;
1169+
1170+
let mut out_sections = HashMap::new();
1171+
for in_section in in_object.sections() {
1172+
if in_section.kind() == SectionKind::Metadata {
1173+
continue;
1174+
}
1175+
let section_id = out_object.add_section(
1176+
in_section.segment_name().unwrap_or("").as_bytes().to_vec(),
1177+
in_section.name().unwrap_or("").as_bytes().to_vec(),
1178+
in_section.kind(),
1179+
);
1180+
let out_section = out_object.section_mut(section_id);
1181+
if out_section.is_bss() {
1182+
out_section.append_bss(in_section.size(), in_section.align());
1183+
} else {
1184+
out_section.set_data(in_section.uncompressed_data().into(), in_section.align());
1185+
}
1186+
out_sections.insert(in_section.index(), section_id);
1187+
}
1188+
1189+
let mut out_symbols = HashMap::new();
1190+
for (symbol_index, in_symbol) in in_object.symbols() {
1191+
if in_symbol.kind() == SymbolKind::Null {
1192+
continue;
1193+
}
1194+
let (section, value) = match in_symbol.section_index() {
1195+
Some(index) => (
1196+
Some(*out_sections.get(&index).unwrap()),
1197+
in_symbol.address() - in_object.section_by_index(index).unwrap().address(),
1198+
),
1199+
None => (None, in_symbol.address()),
1200+
};
1201+
let in_sym_name = in_symbol.name().unwrap_or("");
1202+
let sym_name = if in_sym_name.starts_with("PyInit_") {
1203+
format!("PyInit_{}", name.replace(".", "_"))
1204+
} else {
1205+
String::from(in_sym_name)
1206+
};
1207+
1208+
let out_symbol = write::Symbol {
1209+
name: sym_name.as_bytes().to_vec(),
1210+
value,
1211+
size: in_symbol.size(),
1212+
kind: in_symbol.kind(),
1213+
scope: in_symbol.scope(),
1214+
weak: in_symbol.is_weak(),
1215+
section,
1216+
};
1217+
let symbol_id = out_object.add_symbol(out_symbol);
1218+
out_symbols.insert(symbol_index, symbol_id);
1219+
}
1220+
1221+
for in_section in in_object.sections() {
1222+
if in_section.kind() == SectionKind::Metadata {
1223+
continue;
1224+
}
1225+
let out_section = *out_sections.get(&in_section.index()).unwrap();
1226+
for (offset, in_relocation) in in_section.relocations() {
1227+
let symbol = match in_relocation.target() {
1228+
RelocationTarget::Symbol(symbol) => *out_symbols.get(&symbol).unwrap(),
1229+
RelocationTarget::Section(section) => {
1230+
out_object.section_symbol(*out_sections.get(&section).unwrap())
1231+
}
1232+
};
1233+
let out_relocation = write::Relocation {
1234+
offset,
1235+
size: in_relocation.size(),
1236+
kind: in_relocation.kind(),
1237+
encoding: in_relocation.encoding(),
1238+
symbol,
1239+
addend: in_relocation.addend(),
1240+
};
1241+
out_object
1242+
.add_relocation(out_section, out_relocation)
1243+
.unwrap();
1244+
}
1245+
}
1246+
1247+
out_object.write().unwrap()
1248+
}
1249+
11541250
#[derive(Debug)]
11551251
pub struct LibpythonInfo {
11561252
path: PathBuf,
@@ -1341,7 +1437,9 @@ pub fn link_libpython(
13411437
for (i, object_data) in em.object_file_data.iter().enumerate() {
13421438
let out_path = temp_dir_path.join(format!("{}.{}.o", name, i));
13431439

1344-
fs::write(&out_path, object_data).expect("unable to write object file");
1440+
let out_data = rename_init(name, object_data);
1441+
1442+
fs::write(&out_path, out_data).expect("unable to write object file");
13451443
build.object(&out_path);
13461444
}
13471445

0 commit comments

Comments
 (0)