Skip to content

Instantly share code, notes, and snippets.

@viktorholk
Last active July 9, 2025 07:11
Show Gist options
  • Select an option

  • Save viktorholk/1a0f94cb0fec1fc4526336c5e8078aa8 to your computer and use it in GitHub Desktop.

Select an option

Save viktorholk/1a0f94cb0fec1fc4526336c5e8078aa8 to your computer and use it in GitHub Desktop.
The semacode-ruby19 gem v0.7.4 contains C extensions that fail to compile on modern macOS systems due to compatibility issues. This script builds the gem in a compatible Docker environment and creates a precompiled version that works with both direct Ruby usage and Bundler. Using Rbenv
#!/bin/bash
set -e # Exit on any error
# Configuration
GEM_NAME="semacode-ruby19"
GEM_VERSION="0.7.4"
CONTAINER_NAME="semacode-builder"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Logging functions
log() { echo -e "${GREEN}[$(date +'%H:%M:%S')] $1${NC}"; }
error() { echo -e "${RED}[ERROR] $1${NC}" >&2; }
warn() { echo -e "${YELLOW}[WARNING] $1${NC}"; }
# Clean existing installations
cleanup_existing() {
log "Cleaning existing semacode installations..."
gem uninstall semacode-ruby19 --force >/dev/null 2>&1 || true
rm -rf ~/.rbenv/versions/*/lib/ruby/gems/*/gems/semacode-ruby19-* 2>/dev/null || true
rm -rf ~/.rbenv/versions/*/lib/ruby/gems/*/specifications/semacode-ruby19-* 2>/dev/null || true
rm -rf ~/.rbenv/versions/*/lib/ruby/gems/*/extensions/*/semacode-ruby19-* 2>/dev/null || true
rm -rf ~/.rbenv/versions/*/lib/ruby/gems/*/cache/semacode-ruby19-* 2>/dev/null || true
log "✓ Existing installations cleaned"
}
# Check if Docker is running
check_docker() {
if ! docker info >/dev/null 2>&1; then
error "Docker is not running. Please start Docker and try again."
exit 1
fi
}
# Build gem in Docker
build_in_docker() {
log "Building Docker image..."
cat > Dockerfile.semacode << 'EOF'
FROM ruby:2.5-slim
RUN apt-get update && apt-get install -y build-essential wget && rm -rf /var/lib/apt/lists/*
WORKDIR /build
EOF
docker build -f Dockerfile.semacode -t semacode-builder --platform=linux/arm64 . >/dev/null
log "Downloading and compiling gem in container..."
docker run --name ${CONTAINER_NAME} --platform=linux/arm64 -d semacode-builder tail -f /dev/null >/dev/null
docker exec ${CONTAINER_NAME} bash -c "
gem fetch ${GEM_NAME} --version ${GEM_VERSION}
gem install ${GEM_NAME}-${GEM_VERSION}.gem --local --no-document
gem unpack ${GEM_NAME}-${GEM_VERSION}.gem
" >/dev/null
log "✓ Gem compiled successfully in Docker"
}
# Copy compiled files from container
copy_from_container() {
log "Copying compiled files..."
mkdir -p output
# Get gem directory paths
local gem_dir=$(docker exec ${CONTAINER_NAME} ruby -e "puts Gem.dir")
# Copy the installed gem (with compiled extensions)
docker cp ${CONTAINER_NAME}:${gem_dir}/gems/${GEM_NAME}-${GEM_VERSION} output/ >/dev/null
docker cp ${CONTAINER_NAME}:${gem_dir}/specifications/${GEM_NAME}-${GEM_VERSION}.gemspec output/ >/dev/null
log "✓ Files copied from container"
}
# Create precompiled gem
create_precompiled_gem() {
log "Creating Bundler-compatible gem..."
# Use the installed gem (has compiled extensions) and remove ext directory
cp -r output/${GEM_NAME}-${GEM_VERSION} precompiled/
rm -rf precompiled/ext
# Fix gemspec - remove extensions line and update files list
cp output/${GEM_NAME}-${GEM_VERSION}.gemspec precompiled/
sed -i '' '/s\.extensions/d' precompiled/${GEM_NAME}-${GEM_VERSION}.gemspec
sed -i '' 's/"ext\/extconf\.rb"/"lib\/semacode_native.so", "lib\/semacode.rb"/' precompiled/${GEM_NAME}-${GEM_VERSION}.gemspec
# Build and install the fixed gem
cd precompiled
gem build ${GEM_NAME}-${GEM_VERSION}.gemspec >/dev/null
gem install ${GEM_NAME}-${GEM_VERSION}.gem --local --no-document >/dev/null
cd ..
log "✓ Precompiled gem installed"
}
# Test installation
test_gem() {
log "Testing gem functionality..."
if ruby -e "require 'semacode'; sema = DataMatrix::Encoder.new('test'); puts \"Size: #{sema.width}x#{sema.height}\"" >/dev/null 2>&1; then
log "✓ Gem works perfectly!"
return 0
else
error "Gem test failed"
return 1
fi
}
# Cleanup Docker
cleanup_docker() {
docker stop ${CONTAINER_NAME} >/dev/null 2>&1 || true
docker rm ${CONTAINER_NAME} >/dev/null 2>&1 || true
docker rmi semacode-builder >/dev/null 2>&1 || true
rm -f Dockerfile.semacode
rm -rf precompiled
}
# Main execution
main() {
log "🚀 Starting semacode-ruby19 build process..."
# Setup cleanup trap
trap cleanup_docker EXIT
# Execute build steps
cleanup_existing
check_docker
build_in_docker
copy_from_container
create_precompiled_gem
if test_gem; then
log "🎉 SUCCESS! Semacode gem is ready to use!"
log " - Works with: require 'semacode'"
log " - Works with: bundle install"
log " - Built gem saved: ./precompiled/${GEM_NAME}-${GEM_VERSION}.gem"
else
error "Build completed but gem test failed"
exit 1
fi
}
# Run if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
@viktorholk
Copy link
Author

This is the error when installing on newer MacOS.
Previous fix was to downgrade XCode to 11.5, but this is no longer a solution.

Installing semacode-ruby19 0.7.4 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/user/.rbenv/versions/2.5.9/lib/ruby/gems/2.5.0/gems/semacode-ruby19-0.7.4/ext
/Users/user/.rbenv/versions/2.5.9/bin/ruby -r ./siteconf20250708-43248-1rhnmf7.rb extconf.rb
creating Makefile

current directory: /Users/user/.rbenv/versions/2.5.9/lib/ruby/gems/2.5.0/gems/semacode-ruby19-0.7.4/ext
make "DESTDIR=" clean

current directory: /Users/user/.rbenv/versions/2.5.9/lib/ruby/gems/2.5.0/gems/semacode-ruby19-0.7.4/ext
make "DESTDIR="
compiling iec16022ecc200.c
iec16022ecc200.c:284:80: warning: data argument not used by format string [-Wformat-extra-args]
  284 |                      rb_raise(rb_eArgError,  "cannot encode character in X12", c);
      |                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
iec16022ecc200.c:299:80: warning: data argument not used by format string [-Wformat-extra-args]
  299 |                      rb_raise(rb_eArgError,  "cannot encode character in X12", c);
      |                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
iec16022ecc200.c:323:89: warning: data argument not used by format string [-Wformat-extra-args]
  323 |                            rb_raise(rb_eRuntimeError,  "this should not be happening!", c);
      |                                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
iec16022ecc200.c:498:9: error: incompatible pointer to integer conversion initializing 'VALUE' (aka 'unsigned long') with an expression of type 'void *' [-Wint-conversion]
  498 |   VALUE rb_str = NULL;
      |         ^        ~~~~
iec16022ecc200.c:908:12: warning: assigning to 'unsigned char *' from 'char *' converts between pointers to integer types where one is of the unique plain 'char' type and the other is not [-Wpointer-sign]
  908 |       grid = ALLOC_N(char, W * H);
      |            ^ ~~~~~~~~~~~~~~~~~~~~
4 warnings and 1 error generated.
make: *** [iec16022ecc200.o] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/user/.rbenv/versions/2.5.9/lib/ruby/gems/2.5.0/gems/semacode-ruby19-0.7.4 for inspection.
Results logged to /Users/user/.rbenv/versions/2.5.9/lib/ruby/gems/2.5.0/extensions/-darwin-24/2.5.0/semacode-ruby19-0.7.4/gem_make.out

An error occurred while installing semacode-ruby19 (0.7.4), and Bundler cannot continue.
Make sure that `gem install semacode-ruby19 -v '0.7.4' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  semacode-ruby19```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment