0

Im deploying a sinatra webapp that makes use of a c library, through Ruby FFI. I need this library to be compiled on the target machine. I do this through a Rakefile normally, but because of Heroku's ephemeral hard drive, any time I run rake the compiled files dissappear. How can I make these libraries persist? Is there a way to push the files to git from heroku?

Possibly related: Whenever I try to access the page, the application crashes with a code=H10 error. The app runs fine locally.

My attempt at customizing a buildpack:

#!/usr/bin/env ruby

# This script compiles an application so it can run on Heroku.
# It will install the application's specified version of Ruby, it's dependencies
# and certain framework specific requirements (such as calling `rake assets:precompile`
# for rails apps). You can see all features described in the devcenter
# https://devcenter.heroku.com/articles/ruby-support
$stdout.sync = true

$:.unshift File.expand_path("../../../lib", __FILE__)
require "language_pack"
require "language_pack/shell_helpers"

begin

   # my addition begins here
  `mkdir /app/src`
  `cd /app && curl -s https://www.astro.com/ftp/swisseph/swe_unix_src_2.10.02.tar.gz | tar xzvf -`
  `cd '/app/src' && make libswe.so`
   # my addition ends here

  LanguagePack::ShellHelpers.initialize_env(ARGV[2])
  if pack = LanguagePack.detect(ARGV[0], ARGV[1])
    pack.topic("Compiling #{pack.name}")
    pack.log("compile") do
      pack.compile
    end
  end
rescue Exception => e
  LanguagePack::ShellHelpers.display_error_and_exit(e)
end

Alternatively, I also tried:

#!/usr/bin/env bash
# The actual compilation code lives in `bin/support/ruby_compile`. This file instead
# bootstraps the ruby needed and then executes `bin/support/ruby_compile`

BUILD_DIR=$1
CACHE_DIR=$2
ENV_DIR=$3
BIN_DIR=$(cd $(dirname $0); pwd)
BUILDPACK_DIR=$(dirname $BIN_DIR)

# my addition begins here
mkdir /app/src
cd /app && curl -s https://www.astro.com/ftp/swisseph/swe_unix_src_2.10.02.tar.gz | tar xzvf -
cd '/app/src' && make libswe.so
# my addition ends here

source "$BIN_DIR/support/bash_functions.sh"
heroku_buildpack_ruby_install_ruby "$BIN_DIR" "$BUILDPACK_DIR"

if detect_needs_java "$BUILD_DIR"; then
  cat <<EOM

       ## Warning: Your app needs java

       The Ruby buildpack determined your app needs java installed
       we recommend you add the jvm buildpack to your application:

         $ heroku buildpacks:add heroku/jvm --index=1

-----> Installing Java

EOM

  compile_buildpack_v2 "$BUILD_DIR" "$CACHE_DIR" "$ENV_DIR" "https://buildpack-registry.s3.us-east-1.amazonaws.com/buildpacks/heroku/jvm.tgz" "heroku/jvm"
fi

$heroku_buildpack_ruby_dir/bin/ruby $BIN_DIR/support/ruby_compile $@

Both seem to work at first (i.e. compile the C library, output the files I need), but when I run heroku run bash or the web application Im not able to find the files. This is the specific error, btw:

/app/vendor/bundle/ruby/3.0.0/gems/ffi-1.15.5/lib/ffi/library.rb:145:in `block in ffi_lib': Could not open library '/app/src/libswe.so': /app/src/libswe.so: cannot open shared object file: No such file or directory (LoadError)

I've also tried heroku release phase, but even then the files did not persist. Procfile:

release: bundle exec rake
web: bundle exec thin start -R config.ru -e $RACK_ENV -p ${PORT:-5000} 

Rakefile:

#require "bundler/gem_tasks"

task default: [:clean, :c_build, :get_ephe]

task :clean do
  `rm ./src/libswe.so`
  `rm -rf ephe`
end

task :c_build do
  `wget https://www.astro.com/ftp/swisseph/swe_unix_src_2.10.02.tar.gz`
  `tar xvf swe_unix_src_2.10.02.tar.gz`
  `rm swe_unix_src_2.10.02.tar.gz`
  `cd src && make libswe.so && echo "Compiled Library"` 
end

task :get_ephe do
  `mkdir ephe`
  `wget -P ephe https://www.astro.com/ftp/swisseph/ephe/seas_12.se1`
  `wget -P ephe https://www.astro.com/ftp/swisseph/ephe/seas_18.se1`
  `wget -P ephe https://www.astro.com/ftp/swisseph/ephe/sefstars.txt`
  `wget -P ephe https://www.astro.com/ftp/swisseph/ephe/semo_12.se1`
  `wget -P ephe https://www.astro.com/ftp/swisseph/ephe/semo_18.se1`
  `wget -P ephe https://www.astro.com/ftp/swisseph/ephe/sepl_12.se1`
  `wget -P ephe https://www.astro.com/ftp/swisseph/ephe/sepl_18.se1`
end
  • Building the library should happen during deployment when gems are installed and assets get compiled. – Stefan Jun 24 '22 at 04:50
  • How can I make heroku build the library at that time? – Parker McGowan Jun 24 '22 at 16:51
  • Haven't used Heroku in a while, but I think you can create a custom [buildpack](https://devcenter.heroku.com/articles/buildpacks) (or maybe there already is one in the [buildpacks library](https://elements.heroku.com/buildpacks)) – Stefan Jun 24 '22 at 17:11
  • It seems like there is a way to run rake files through the ruby buildpack, which I am using. But I can't find out how to do it in a way that persists. I added a rake proc to the Procfile, but when I heroku run bash in and ls, the folders rake is supposed to create aren't present, and then heroku errors out with H10 – Parker McGowan Jun 24 '22 at 19:09
  • I have been trying to customize the ruby buildpack to compile the requisite C library. I can get the file downloaded and compiled during the compilation stage, but it seems to disappear once that stage is over. I really don't know what I am doing, but I think this should be working, hacky as it is. Added to my OP as an edit – Parker McGowan Jun 25 '22 at 18:45

0 Answers0