Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 162 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,145 @@
# DepSelectorLibgecode

This library vendors Gecode 3.7.3 as a rubygem so it can easily be used
with the [dep-selector](https://github.com/opscode/dep-selector)
project.

[Gecode](http://www.gecode.org) is a fast CSP solver library written in
C++. We created this library to install it in order to optimize the
following criteria:
* Allow users to install libraries that depend on gecode without extra
steps.
* Install the correct version of gecode for dep-selector. The current
release line of gecode is 4.x, but dep-selector uses ~> 3.5.
* Configure the source installation for shortest compilation time by
excluding unnecessary components. Gecode has a reputation for taking a
long time to compile, but in fact most of that time is spent building
examples and documentation. We've disabled these, along with the
flatzinc interpreter.
# dep-selector-libgecode

[![CI](https://github.com/chef/dep-selector-libgecode/actions/workflows/ci.yml/badge.svg)](https://github.com/chef/dep-selector-libgecode/actions/workflows/ci.yml)
[![Gem Version](https://badge.fury.io/rb/dep-selector-libgecode.svg)](https://rubygems.org/gems/dep-selector-libgecode)

This gem vendors the Gecode 3.7.3 C++ library and builds it at install time, so
that [dep-selector](https://github.com/chef/dep-selector) can be installed with
a plain `gem install` and no manual, out-of-band library setup.

[Gecode](https://github.com/Gecode/gecode) is a fast constraint programming
(CSP) solver library written in C++. dep-selector uses it to solve cookbook
dependency graphs. We vendor it here to:

* Let users install gems that depend on Gecode without extra steps.
* Pin the *correct* Gecode version. dep-selector requires Gecode `~> 3.5`, and
the 3.x series is API-incompatible with everything released since.
* Configure the build for the shortest possible compile time. Gecode has a
reputation for taking forever to build, but most of that time goes to the
examples, documentation, Qt bits, and the FlatZinc interpreter — all of which
we disable.

## Project status

This gem is intentionally frozen on Gecode 3.7.3, released in 2012. That is
not an oversight waiting to be fixed here: dep-selector is written against the
Gecode 3 API and does not work with Gecode 4 or later, so moving this gem
forward would mean porting dep-selector first.

A couple of consequences worth knowing in advance:

* The original upstream site, `gecode.org`, is no longer online. The project
now lives at [github.com/Gecode/gecode](https://github.com/Gecode/gecode),
where the current release line is 6.x.
* Because Gecode 3 is so old, compiling it emits a large volume of warnings on
modern compilers (`-Wdeprecated-copy`, `noexcept` destructor notes, and
friends). These are expected and not a sign that the build is broken.

## Installation

Add this line to your application's Gemfile:

gem 'dep-selector-libgecode'
```ruby
gem 'dep-selector-libgecode'
```

And then execute:

$ bundle
```console
$ bundle install
```

Or install it yourself as:

$ gem install dep-selector-libgecode
```console
$ gem install dep-selector-libgecode
```

### Build requirements

Installing the gem compiles Gecode from the vendored source, so a working
toolchain has to be present *before* you install. On Linux, macOS, and other
Unix-like platforms the extension regenerates Gecode's build system with
autotools before configuring, so you need all of:

* A C++ compiler and GNU `make`
* `autoconf`, `automake`, and `libtool` (the build shells out to `libtoolize`,
`aclocal`, `autoheader`, `automake`, `autoconf`, and `autoupdate`)

| Platform | Install the toolchain with |
| --- | --- |
| Debian / Ubuntu | `sudo apt-get install build-essential autoconf automake libtool` |
| Fedora / RHEL | `sudo dnf install gcc-c++ make autoconf automake libtool` |
| macOS | `xcode-select --install` and `brew install autoconf automake libtool` (see the note below) |
| Windows | See [Installation on Windows](#installation-on-windows) below |

On macOS, Homebrew installs GNU libtool as `glibtoolize` to avoid colliding
with Apple's unrelated `libtool`, but the build shells out to plain
`libtoolize`. Put Homebrew's GNU-named symlinks first on your `PATH` before
installing:

```console
$ export PATH="$(brew --prefix libtool)/libexec/gnubin:$PATH"
$ gem install dep-selector-libgecode
```

The build runs `make` with up to five concurrent jobs to shorten compile time,
so it uses roughly 2GB of RAM. On a memory-constrained machine — a small
CI container, for instance — that is the first thing to look at when the build
is killed rather than failing with a compiler error. If that is a problem for
your environment, see [Using a system Gecode
instead](#using-a-system-gecode-instead) below.

## Installation on Windows

* The recommended installation method is
[ChefDK](https://downloads.chef.io/chef-dk/windows/#/) and the following
steps can be skipped if you choose this method.
* Don't set `USE_SYSTEM_GECODE` to anything. The build only checks for the
presence of this variable, not the value.
* Install [ruby](http://rubyinstaller.org/downloads/). Install
[DevKit](http://rubyinstaller.org/add-ons/devkit/)(preferred), or install
[mingw](http://sourceforge.net/projects/mingw/files/) and add it to your
PATH. You can use the Chef omnibus MSI to get a working ruby and devkit.
* Install a working tar, and include it in your PATH. There is a tar binary
that comes with the git package, but it is horribly broken and only good for
generating core dumps. Before you build anything check `where tar` to make sure
the tar from git is not the first one in your PATH. The chef-client omnibus
package has a tar that works (easiest), or you can get one from here:
http://gnuwin32.sourceforge.net/packages/gtar.htm
* `gem install berkshelf` should work now.
* Examples for automating these builds can also be found at
[omnibus-chef](https://github.com/opscode/omnibus-chef) and
[omnibus-software](https://github.com/opscode/omnibus-software).

### Requirements

This gem runs make with concurrent jobs to speed build time, so it uses
about 2GB of RAM during the build. If this doesn't work for your
environment, see 'Using a System Gecode Instead' below. Better yet, if
you only want to install Berkshelf, try using
[ChefDK](http://www.getchef.com/downloads/chef-dk) instead of a gem
install.

### Using a System Gecode Instead

Use the "USE_SYSTEM_GECODE" environment variable when installing to
make dep-selector-libgecode use the system version, instead of
downloading the source and building its own copy:

$ USE_SYSTEM_GECODE=1 gem install dep-selector-libgecode

*WARNING:* Ensure that your system packages provide Gecode version 3 and
not version 4. Version 4 does not work with dep-selector.
Windows does *not* go through autotools; the extension configures and builds
Gecode directly with the MSYS2/MinGW toolchain.

* Install Ruby with [RubyInstaller2](https://rubyinstaller.org/downloads/),
choosing one of the "Ruby+Devkit" installers. Modern RubyInstaller bundles
MSYS2 rather than the long-retired standalone DevKit. After installing, run
`ridk install` and select the MSYS2 base and MinGW development toolchain
options so `gcc`/`g++` and `make` are available.
* Do not set `USE_SYSTEM_GECODE` to anything. The build only checks whether the
variable is *present*, not what it is set to, so `USE_SYSTEM_GECODE=0` will
still skip the vendored build.
* You need a working `tar` on your `PATH`. Windows 10 (1803 and later) and
Windows 11 ship bsdtar as `C:\Windows\System32\tar.exe`, which works fine.
Run `where tar` and confirm that whatever comes back first is not a
third-party tar with a reputation for producing core dumps instead of
archives.
* `gem install dep-selector-libgecode` should work at that point.

Examples of automating these builds can also be found in
[omnibus-software](https://github.com/chef/omnibus-software).

## Using a system Gecode instead

Set the `USE_SYSTEM_GECODE` environment variable when installing to make
dep-selector-libgecode skip the vendored build entirely and link against a
Gecode you already have:

```console
$ USE_SYSTEM_GECODE=1 gem install dep-selector-libgecode
```

**Be careful with this option.** dep-selector needs Gecode 3, and no current
package manager ships Gecode 3 any more:

| Source | Gecode version |
| --- | --- |
| Debian / Ubuntu (`libgecode-dev`) | 6.2.0 |
| Homebrew (`gecode`) | 6.4.0 |

Gecode 4 and later will not work. In practice, `USE_SYSTEM_GECODE` is only
useful if you have built and installed Gecode 3.7.3 yourself, or if you are
packaging this gem inside a larger build (Omnibus, a distro package, a
container image) that supplies its own Gecode 3.

## Usage

`DepSelectorLibgecode` provides helper functions for locating the
vendored gecode after installation:
`DepSelectorLibgecode` provides helper functions for locating the vendored
Gecode after installation:

```ruby
require 'dep-selector-libgecode'
Expand All @@ -88,29 +151,52 @@ DepSelectorLibgecode.opt_path
DepSelectorLibgecode.include_path
```

### Vendoring Native Gems (docs for Maintainers)
Note that when the gem was installed with `USE_SYSTEM_GECODE` set, these paths
point at a directory that was never populated — the caller is expected to be
using the system library's paths instead.

The `rake native` command can be used to build a native "fat" gem.
## Development

It is recommended to use the following process:
Building the gem package itself needs no C++ toolchain, because the extension
is only compiled at install time:

```console
$ gem build dep-selector-libgecode.gemspec
```

To exercise the actual Gecode compile the way an end user would, run the
extension's `extconf.rb` directly. It installs into
`lib/dep-selector-libgecode/vendored-gecode`, which is gitignored:

```console
$ ruby ext/libgecode3/extconf.rb
```
% git clean -ffdx
% git checkout -- .
% rake native
% gem push pkg/dep-selector-libgecode-1.3.0-x86_64-darwin-15.gem # obviously use the filename you actually built here

Both of these run in CI on every push and pull request across the supported
Ruby versions; see [`.github/workflows/ci.yml`](.github/workflows/ci.yml).

### Vendoring native gems (docs for maintainers)

The `rake native` command builds a native "fat" gem with Gecode already
compiled, so that users on that platform do not have to compile anything.

It is recommended to use the following process:

```console
$ git clean -ffdx
$ git checkout -- .
$ rake native
$ gem push pkg/dep-selector-libgecode-1.3.5-arm64-darwin-25.gem # use the filename you actually built
```

Without cleaning up the repo first and nuking stuff in ext/ and pkg/ the `rake native` command will fail.
Without cleaning up the repo first and nuking the artifacts left behind in
`ext/` and `pkg/`, `rake native` will fail.

## Licensing

The packaging code here is released under the terms of the Apache2
license. Gecode itself is released under the terms of the MIT license.

See CONTRIBUTING.md for more information.
The packaging code here is released under the terms of the Apache 2.0 license.
Gecode itself is released under the terms of the MIT license.

## Contributing

See CONTRIBUTING.md for more information.

See [CONTRIBUTING.md](CONTRIBUTING.md) for more information.