# MiniPortile This documents versions 2 and up, for which the require file was renamed to `mini_portile2`. For mini_portile versions 0.6.x and previous, please visit [the v0.6.x branch](https://github.com/flavorjones/mini_portile/tree/v0.6.x). [![travis status](https://travis-ci.org/flavorjones/mini_portile.svg?branch=master)](https://travis-ci.org/flavorjones/mini_portile?branch=master) [![appveyor status](https://ci.appveyor.com/api/projects/status/509669xx1qlhqqab/branch/master?svg=true)](https://ci.appveyor.com/project/flavorjones/mini-portile/branch/master) * Documentation: http://www.rubydoc.info/github/flavorjones/mini_portile * Source Code: https://github.com/flavorjones/mini_portile * Bug Reports: https://github.com/flavorjones/mini_portile/issues This project is a minimalistic implementation of a port/recipe system **for developers**. Because _"Works on my machine"_ is unacceptable for a library maintainer. ## Not Another Package Management System `mini_portile2` is not a general package management system. It is not aimed to replace apt, macports or homebrew. It's intended primarily to make sure that you, as the developer of a library, can reproduce a user's dependencies and environment by specifying a specific version of an underlying dependency that you'd like to use. So, if a user says, "This bug happens on my system that uses libiconv 1.13.1", `mini_portile2` should make it easy for you to download, compile and link against libiconv 1.13.1; and run your test suite against it. This scenario might be simplified with something like this: ``` rake compile LIBICONV_VERSION=1.13.1 ``` (For your homework, you can make libiconv version be taken from the appropriate `ENV` variables.) ## Sounds easy, but where's the catch? At this time (and highly likely will be always) `mini_portile2` is only compatible with **GCC compilers** and **autoconf**- or **configure**-based projects. That is, it assumes the library you want to build contains a `configure` script, which all the autoconf-based libraries do. ### How to use Now that you know the catch, and you're still reading this, here is a quick example: ```ruby gem "mini_portile2", "~> 2.0.0" # NECESSARY if used in extconf.rb. see below. require "mini_portile2" recipe = MiniPortile.new("libiconv", "1.13.1") recipe.files = ["http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz"] recipe.cook recipe.activate ``` The gem version constraint makes sure that your extconf.rb is protected against possible backwards-incompatible changes to `mini_portile2`. This constraint is REQUIRED if you're using `mini_portile2` within a gem installation process (e.g., extconf.rb), because Bundler doesn't enforce gem version constraints at install-time (only at run-time. `#cook` will download, extract, patch, configure and compile the library into a namespaced structure. `#activate` ensures GCC will find this library and prefer it over a system-wide installation. ### Directory Structure Conventions `mini_portile2` follows the principle of **convention over configuration** and established a folder structure where is going to place files and perform work. Take the above example, and let's draw some picture: ``` mylib |-- ports | |-- archives | | `-- libiconv-1.13.1.tar.gz | `-- | `-- libiconv | `-- 1.13.1 | |-- bin | |-- include | `-- lib `-- tmp `-- `-- ports ``` In above structure, `` refers to the architecture that represents the operating system you're using (e.g. i686-linux, i386-mingw32, etc). Inside the platform folder, `mini_portile2` will store the artifacts that result from the compilation process. The library is versioned so you can keep multiple versions around on disk without clobbering anything. `archives` is where downloaded source files are cached. It is recommended you avoid trashing that folder to avoid downloading the same file multiple times (save bandwidth, save the world). `tmp` is where compilation is performed and can be safely discarded. Use the recipe's `#path` to obtain the full path to the installation directory: ```ruby recipe.cook recipe.path # => /home/luis/projects/myapp/ports/i686-linux/libiconv/1.13.1 ``` ### How can I combine this with my compilation task? In the simplest case, your rake `compile` task will depend on `mini_portile2` compilation and most important, activation. Example: ```ruby task :libiconv do recipe = MiniPortile.new("libiconv", "1.13.1") recipe.files << { url: "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz"], md5: "7ab33ebd26687c744a37264a330bbe9a" } checkpoint = ".#{recipe.name}-#{recipe.version}.installed" unless File.exist?(checkpoint) recipe.cook touch checkpoint end recipe.activate end task :compile => [:libiconv] do # ... your library's compilation task ... end ``` The above example will: * **download** and verify integrity the sources only once * **compile** the library only once (using a timestamp file) * ensure compiled library is **activated** * make the compile task depend upon compiled library activation As an exercise for the reader, you could specify the libiconv version in an environment variable or a configuration file. ### Native and/or Cross Compilation The above example covers the normal use case: compiling dependencies natively. `MiniPortile` also covers another use case, which is the cross-compilation of the dependencies to be used as part of a binary gem compilation. It is the perfect complementary tool for [`rake-compiler`](https://github.com/rake-compiler/rake-compiler) and its `cross` rake task. Depending on your usage of `rake-compiler`, you will need to use `host` to match the installed cross-compiler toolchain. Please refer to the examples directory for simplified and practical usage. ### Supported Scenarios As mentioned before, `MiniPortile` requires a GCC compiler toolchain. This has been tested against Ubuntu, OSX and even Windows (RubyInstaller with DevKit) ## License This library is licensed under MIT license. Please see LICENSE.txt for details.