My Failure Experiences of Making a Homebrew Formula

It is the first time that I want to write something I failed.  A week ago, I tried to submit dbr (Dynamsoft Barcode Reader) to homebrew/core. In spite of passing auto checks, my formula was finally rejected. This article records everything I went through during this process.

What is Homebrew

Homebrew is a package manager for macOS. It is similar to Chocolatey for Windows and apt-get for Ubuntu. Not like other package managers hosting all resource files, Homebrew is a decentralized tool that only maintains ruby script files. Contributors need to host resource files themselves and submit a formula (a Ruby script) to Homebrew GitHub repository.

How to Create a Homebrew Formula

Formula Cookbook is the place for you.

Automatically generate a new formula for your package URL:

brew create https://download2.dynamsoft.com/dbr/dbr-mac-5.2.0.zip

The version can be determined by URL if you use the pattern PackageName-Version.

Take a look at /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/dbr-mac.rb:

# Documentation: https://docs.brew.sh/Formula-Cookbook.html$

#                http://www.rubydoc.info/github/Homebrew/brew/master/Formula$

# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!$

$

class DbrMac < Formula$

desc ""$

homepage ""$

url "https://download2.dynamsoft.com/dbr/dbr-mac-5.2.0.zip"$

sha256 "34fa6a39ace60f768b2bd46606ac995d3a3881a8169313f6aeabefa2dae08c38"$

$

# depends_on "cmake" => :build$

$

def install$

    # ENV.deparallelize  # if your formula fails when building in parallel$

$

    # Remove unrecognized options if warned by configure$

    system "./configure", "--disable-debug",$

                        "--disable-dependency-tracking",$

                        "--disable-silent-rules",$

                        "--prefix=#{prefix}"$

    # system "cmake", ".", *std_cmake_args$

    system "make", "install" # if this fails, try separate make/make install steps$

end$

$

test do$

    # \`test do\` will create, run in and delete a temporary directory.$

    #$

    # This test will fail and we won't accept that! For Homebrew/homebrew-core$

    # this will need to be a test that verifies the functionality of the$

    # software. Run the test with \`brew test dbr-mac\`. Options passed$

    # to \`brew install\` such as \`--HEAD\` also need to be provided to \`brew test\`.$

    #$

    # The installed folder is not in the path, so use the entire path to any$

    # executables being tested: \`system "#{bin}/program", "do", "something"\`.$

    system "false"$

end$

end$

Do nothing and save the file. Change the directory to /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core and check the info:

cd $(brew --repo homebrew/core)
brew info --new-formula dbr-mac

Homebrew info

Run `brew audit’ to test the formula:

brew audit --new-formula dbr-mac

Homebrew audit

To fix the errors, add description and homepage, and remove default template comments. Because my target package only contains header files and libraries, I also removed configure' and make ‘ commands. Here is the final look:

class DbrMac < Formula$

  desc "Barcode SDK for 1D, QRCode, DataMatrix and PDF417"$

  homepage "https://www.dynamsoft.com/Products/Dynamic-Barcode-Reader.aspx"$

  url "https://download2.dynamsoft.com/dbr/dbr-mac-5.2.0.zip"$

  sha256 "34fa6a39ace60f768b2bd46606ac995d3a3881a8169313f6aeabefa2dae08c38"$

  test do$

    system "false"$

  end$

end$

I can pass the test now.

How to write the Ruby script for Homebrew formula

To figure out how to install resources and write a test, you’d better study the existing formulae.

Note: if you don’t have a test script, you can pass brew audit. But it will fail after building by Jenkins.

Fork https://github.com/Homebrew/homebrew-core and clone the repo. All Ruby scripts are under homebrew-core/Formula/ folder. Installing resources is easy:

def install
    include.install Dir["BarcodeReader5.2/include/*"]
    lib.install "BarcodeReader5.2/lib/libDynamsoftBarcodeReader.dylib"
    doc.install Dir["BarcodeReader5.2/documents/*"]
end

How to write the test? My package contains a .dylib file. So write a simple C program and test whether there is any library linking issue.

test do
    (testpath/"test.c").write <<~EOS
      #include <stdio.h>
      #include "DynamsoftBarcodeReader.h"
      int main(int argc, char ** argv)
      {
        void* hBarcode = DBR_CreateInstance();
        DBR_DestroyInstance(hBarcode);
        return 0;
      }
    EOS
    system ENV.cc, "test.c", "-L#{lib}", "-lDynamsoftBarcodeReader", "-o", "test"
    system "./test"
end

Why was my formula rejected?

Everything seemed okay, though, the formula was declined in the end. According to the policy, Homebrew only ships open source software that builds from source. So it will fail if you submit binary formulae.