Last active
May 2, 2023 11:50
-
-
Save pbosetti/cdb6b6abee5263cd8939cc4377d78d4c to your computer and use it in GitHub Desktop.
Script for generating stub dynamic libraries for cross compilation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# This script can create stub C libraries that are useful in cross-compilation | |
# tasks. | |
# Usage: | |
# ./mkstub.rb <path to original library file> [linux|macos] | |
# This will generate a stub file, a compiled shared object for the local system, | |
# and a shell script named compile_<libname>_stub.sh. The latter shall be copied | |
# to the target system (specified by the optional second argument), which | |
# doesn't have the library of matter, and executed, resulting in a shared object | |
# that represents a stub of the original library. A stub library has all the | |
# exported symbols of the original one, although they are all aliases to the | |
# same blank function. It can be safely used as a replacement of the original | |
# library for linking purpose. | |
class String | |
def red() "\e[0;31m" + self + "\e[0m"; end | |
def green() "\e[0;32m" + self + "\e[0m"; end | |
def yellow() "\e[0;33m" + self + "\e[0m"; end | |
def blue() "\e[0;34m" + self + "\e[0m"; end | |
end | |
lib_path = ARGV[0] | |
lib_name = File::basename(lib_path, ".*") | |
stub_name = "so_stub_for_#{lib_name}".sub("-", "_") | |
stub_file = "stubs.c" | |
puts "Generating stub library for symbols defined in #{lib_path}...".green | |
names = `nm #{lib_path}` | |
defsyms = names.split("\n") | |
.map {|n| l = n.split(" "); l[1..2]} | |
.filter {|e| e[0] == "T"} | |
# Local system | |
if (/darwin/ =~ RUBY_PLATFORM) | |
local_defsyms = defsyms.map {|n| "-Wl,-alias,_#{stub_name},#{n[1]}"} | |
local_lib_ext = ".dylib" | |
else | |
local_defsyms = defsyms.map {|n| "-Wl,--defsym,#{n[1]}=#{stub_name}"} | |
local_lib_ext = ".so" | |
end | |
# Target system | |
target = ARGV[1] || "linux" | |
if (/^[lL]/ =~ target) | |
target = "Linux" | |
lib_ext = ".so" | |
defsyms.map! {|n| | |
n[1] = n[1][1..-1] if n[1][0] == "_" | |
"-Wl,--defsym,#{n[1]}=#{stub_name}" | |
} | |
elsif (/^[mM]/ =~ target) | |
target = "MacOS" | |
lib_ext = ".dylib" | |
defsyms.map! {|n| "-Wl,-alias,_#{stub_name},#{n[1]}"} | |
else | |
puts "Unsupported target system #{target}".red | |
exit -1 | |
end | |
puts "Found #{defsyms.length} symbols" | |
c_file = DATA.read | |
File.write(stub_file, c_file) | |
puts "Created stub file #{stub_file}" | |
puts "Compiling with command:" | |
defsym = defsyms.join(" ") | |
local_defsym = local_defsyms.join(" ") | |
defines = "-DFNAME=#{stub_name}"; | |
puts "g++ -shared -Wall -fPIC #{defines} stubs.c #{local_defsyms[1]} ".blue + "[#{local_defsyms.length} more]".red + " -o #{lib_name}#{lib_ext}".blue | |
local_compile_cmd = "-shared -Wall -fPIC #{defines} #{local_defsym} -o #{lib_name}#{local_lib_ext} -Wno-deprecated" | |
compile_cmd = "-shared -Wall -fPIC #{defines} #{defsym} -o #{lib_name}#{lib_ext} -Wno-deprecated" | |
system("gcc " + local_compile_cmd + " stubs.c") | |
puts "Stub library generated as " + "#{lib_name}#{local_lib_ext}".green | |
puts "Generating script for target system #{target.green}..." | |
File.open("compile_#{lib_name}_stub.sh", "w") do |f| | |
f.print <<~EOF | |
#!/bin/sh | |
# Stub generator for creating stub #{lib_name} on #{target} systems | |
# Check OS | |
if [[ $OSTYPE != #{target == "Linux" ? "linux" : "darwin"}* ]]; then | |
echo "This script is supposed to run on #{target} only." | |
exit 1 | |
fi | |
# default compiler | |
if [ -z "$CC"]; then CC=gcc; fi | |
# find last line +1 | |
SCRIPT_END=$(awk '/^__PAYLOAD__/ { print NR + 1; exit 0; }' $0) | |
STUB_FILE="#{lib_name}_stub.c" | |
# Extract file | |
echo "Creating $STUB_FILE (#{target} platform)" | |
tail -n +$SCRIPT_END $0 > $STUB_FILE | |
# compile | |
echo "Compiling $STUB_FILE > #{lib_name}#{lib_ext}" | |
${CC} #{compile_cmd} #{lib_name}_stub.c | |
exit 0 | |
__PAYLOAD__ | |
#{c_file} | |
EOF | |
end | |
File.chmod(0755, "compile_#{lib_name}_stub.sh") | |
puts "Script " + "compile_#{lib_name}_stub.sh".green + " generated. Copy that on target system and run it" | |
puts "Done.".green | |
__END__ | |
// Created by mkstubs.rb script | |
#include <stdio.h> | |
#include <stdlib.h> | |
void FNAME() { | |
fprintf(stderr, "%s: this is a stub, real library not available\n", __func__); | |
abort(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment