Advanced Topics
Patches
Compile
has built-in support for applying patches distributed with recipes.
There are some things that should be considered when creating a patch for an
application. First of all, if the patch is generic, consider sending it
upstream, to the original project, as well. If that is done, here is how one
should do to get the patch working with Compile
.
Patch structure
Compile
applies the patch from within the source directory with the -p1
option, stripping one directory from the patch’s search path. This is to ensure
that the patch is appliable without editing even if the recipe is updated. The
patch should therefore add one level to the source directory in the path. An
example taken from the rlocate
recipe, created with diff
:
--- rlocate-0.4.3/doc/rlocate.html 2006-01-19 10:04:52.000000000 +0100
+++ rlocate-0.4.3.new/doc/rlocate.html 2006-01-19 19:10:20.000000000 +0100
@@ -223,6 +223,6 @@
Set the permissions of the rlocate and rlocated binaries. To do this execute the following commands:
- chown root:rlocate /usr/local/bin/rlocate
+ chown 0:rlocate /usr/local/bin/rlocate
chmod 2755 /usr/local/bin/rlocate
This diff should then be in a file, say 01-root_to_uid.patch
, wich is placed
in the Rlocate 0.4.3
recipe directory. Of course the filename should be
somewhat descriptive to what the patch does. The filename should also be
prefixed with a number, which ensures that the patches are applied in the
correct order, as there can be a number of patches, some of them being applied
to the same source file.
Creating a patch
To create a patch you need the edited source and the “clean” source, then use
diff
to create the patch. To create the patch in the example above I used
cd /Data/Compile/Sources
diff -Naur rlocate-0.4.3 rlocate-0.4.3.new > 01-root_to_uid.patch
where rlocate-0.4.3.new
was the directory holding the edited source. This may
work if you only have one type of change made. But if you made several different
edits and want them in different patches one can specify the exact file to
‘diff’ or you can make a full diff and edit the resulting file, spliting it into
smaller patches.
Converting patches
Perhaps there are already patches for the project, but they have the wrong path
in them. You can experience that the patches wont apply, even though they are
made for the specific application and version you are trying to Compile
.
Either you can edit the patches and add or remove directories to the patch (more
precisely to the rows string with +++
and ---
,
--- rlocate-0.4.3/doc/rlocate.html 2006-01-19 10:04:52.000000000 +0100
in the
example above), so that there are exactly one directory above the source
directory. This can be tedious if it is a big patch. Then an easier way is to
apply the patch to the source and make a diff between the patched source and a
“clean” copy, just as when you create a new patch.
Dynamic patches
Sometimes you want to add paths to the patches that are dependent on the host
system the application is installed on. Instead of adding the path statically to
the patch Compile
has support for dynamically created patches. By placing the
suffix .in
, e.g. 01-root_to_uid.patch.in
, on the patch you tell Compile
that it should parse the file and generate the patch 01-root_to_uid.patch
,
with certain strings replaced with values dependant on the system. The same
variables used in
recipes can be used
in patches but prefixed with the string Compile_
and padded with @%
and
%@
. So, for example, if rlocate
depended on the application foo
, the
variable used in recipes to reference foo
’s installation directory would be
$foo_path
and therefore the string used in patches to reference this path
would be @%Compile_foo_path%@
. Below are valid variables for target
application as well as directories belonging to the dependency foo
:
@%Compile_target%@
@%Compile_settings_target%@
@%Compile_variable_target%@
@%Compile_foo_path%@
@%Compile_foo_settings_path%@
@%Compile_foo_variable_path%@
Binary recipes
Full article: Binary recipes
Binary recipes are used to install vendor-supplied precompiled binaries of
software. They are usually created using the manifest recipe type, and have
_bin
suffixed to their version.
Recipe types
See also: Recipe types reference
The Compile
tool can handle numerous types of packages, each of them with a
different build technique.
When MakeRecipe
is invoked, it downloads the
program’s source, uncompresses it and tries to detect what kind of build system
it uses. And, surely, there are some packages on which
MakeRecipe
cannot detect that. This is when the
user’s interaction is needed, and some manual modifications on the Recipe must
be done.
As presented in the Compile
section, Compile
handles
compilation of programs according to a few number of “recipe types”. For each
type, there are valid declarations that you can specify, to adapt the behavior
of Compile
to the needs of the program that is about to be compiled. The full
list of declarations is at Appendix “Recipe format
specification”. Let’s see some of the
main options for each type:
configure recipes
These are autoconf-based packages, and are indicated with
recipe_type=configure
. The most common variation in recipes of this type is
the need to pass additional flags to the configure
script. You can do so with
the configure_options
flag, like this:
configure_options=(
"--enable-shared"
"--with-foo"
)
Keep in mind that by passing explicit flags to configure, you are affecting
the dependencies of the package. Ideally, the configure script should be
able to detect what’s available in the system and enable or disable features.
Much progress in this area has been made in the last few years, especially with
Pkgconfig
, but still some programs require
flags to be passed explicitly.
In configure-based recipes, Compile
uses
PrepareProgram
to detect if some standard
parameters such as --prefix
are supported by the configure script. If the
program does not support these parameters and
PrepareProgram
detects them incorrectly, you
can use override_default_options=yes
to have configure
use only the
options given by you in configure_options
.
Another occasionally necessary flag is autogen_before_configure=yes
. Some
programs distribute the necessary input files for generating configure
(such
as configure.ac
or configure.in
) but do not ship the generated script, only
a builder script autogen.sh
. Using this flag, autogen.sh
will be executed as
a first step.
If configure or autogen.sh have non-standard names, you can explicitly
provide them with configure
and autogen
, like this:
configure=configure.gnu
autogen=gen_all.sh
If present at <architecture>/Recipe
, an architecture-specific Recipe file is
sourced in addition to the base Recipe file. Variable assignments in it will
override earlier ones, so to append to a variable, you must do so explicitly,
e.g.
configure_options=(
"${configure_options[@]}"
--with-cpu=i686
--enable-add-ons
)
Since “compileprogram” recipes also run make
, most of the observations about
“makefile” recipes, discussed below also apply.
makefile recipes
These are packages that use Makefiles directly. You can easily spot programs
of these type: when the program’s installation instructions just tell you to run
make
from command line without a previous step, they are recipes of this kind.
For this kind of recipe, Compile
runs make
twice: the “build” run and the
“install” run. A few programs require only one run; you can disable either with
do_build=no
and do_install=no
.
In “makefile” recipes, you will always have to pass at least one additional
option in the recipe, to tell the Makefile to use the
/Programs/program-name>/version>
directory. If we’re lucky, the Makefile has
one main variable that controls the installation prefix. Variables of this kind
are usually called PREFIX
, DESTDIR
, INSTDIR
… you’ll have to look inside
the Makefile
to find out. Remember that the installation prefix is set by
Compile
as the target
shell variable. To give make
variables, we can
either use build_variables
and install_variables
, which give options to the
“build” and “install” runs of make
, or just make_variables
which passes
options to both runs. Their use is similar to that of configure_options
.
make_variables=(
"DESTDIR=$target"
)
Sometimes, paths are defined in several variables of the Makefile
. No problem:
make_variables=(
"BINDIR=$target/bin"
"LIBDIR=$target/lib"
"ETCDIR=$target/../Settings"
)
If there are no variables of this kind in the Makefile
, that is, if the
Makefile
has hard-coded locations in its installation rules, then
unfortunately you’ll have to patch the Makefile
(and possibly the source code,
look for references to paths like /usr
using grep
).
Like with configure
and autogen
, if the makefile uses a different name from
the standard (Makefile
), you can pass it explicitly using the makefile
variable:
makefile=GNUmakefile
python recipes
The “python” recipe type is used for programs using Python Distutils as a build
system. Since it is so recent, there is a number of minor variations floating
around (some packages use setup.py
, others use build.py
, etc.) – “python”
tries to detect these variations where possible, but ultimately there are flags
to specify special cases explicitly.
The name of the build script can be given with build_script
. You can control
the two runs of the Python build script using the same options as “makefile
recipes” (do_build=no
and do_install=no
to disable runs, build_target
and
install_target
to name the runs). Custom options can be passed with
python_options
. Again, override_default_options=yes
can be passed to skip
auto-detected flags if needed.
xmkmf recipes
This is for recipes based on the old “xmkmf –>–> imake” system historically used by the X Window System. This is being phased out in Xorg 7.0 in favor of GNU autoconf.
scons recipes
This is for recipes based on SCons.
manifest recipes
“Manifest” recipes are used for programs that just need to copy files over. The
manifest
array-style entry lists colon-separated pairs, indicating source file
and target destination, relative to target
. (See “Recipe format
specification” for details).