#
# title: Preprocessor
# description: Apply preprocessor on source input files.
# version: 0.2
# depends: bin:preprocess
# api: fpm
# type: rewrite
# category: source
#
# This update filter is intended solely for packaging scripting language apps,
# not as C/C++ build helper. In particular scripting languages without unified
# build processing tool chains can use C-style macros this way.
#
# Note that it utilizes "preprocess.py" instead of CPP (which conflicts with
# the comment syntax of most scripting languages). Therefore macros take the
# forms:
#
# # #define X Y (Perl, Python, PHP, Tcl, Ruby, Shell, Text)
# # #ifdef X
# // #elif "foo" in BAR (Java, PHP, C++, C#, IDL)
# // #include "file.h"
# /* #undef Y */ (CSS, C, JavaScript)
# /* #endif */
# <!-- #if defined(Z) --> (HTML, XML)
#
# This allows to utilize #include ".." or #ifdef chains to merge sources to
# packaging variants, or simply inject custom constants at generation time.
# One could just supply a -D VERSION=1.2.3 constant. (Two predefined constants
# are `__DIST_VERSION` and `__DIST_PACKAGE` btw.)
#
# → Use `-u cpp=php` to apply it for specific file extensions.
# → Any `-I dir/file` can be used for including files or header directories.
# → And `-D CONST=1` to inject custom defines.
#
# Obviously this is a workaround for Perl/PHP/Python/Ruby/etc. which could only
# runtime-load dependencies, but don't provide build tools (apart from scripted
# packagers) to conjoin source code etc.
#
require "fpm/package"
require "fpm/util"
require "fileutils"
require "shellwords"
class FPM::Package::Filter_preprocess < FPM::Package
option "-I", "dir", "Preprocessor include directories", :asis => true, :hidden => true, :attribute_name => "cpp_include",
:multivalued => true do |file| next ("-I#{File.expand_path(file)}") end
option "-D", "CONST=VAL", "Preprocessor macro definitions", :asis => true, :hidden => true, :attribute_name => "cpp_define",
:multivalued => true do |d| next ("-D#{d}") end
# run files through preprocessor of sorts
def update(opts)
incinc = ["-I.", "-I#{staging_path}", "-I/usr/include/php5/main", "-I/usr/include/ruby-2.0.0"]
includes = (attributes[:cpp_include] + incinc).join(" ")
defdef = ["-D__DIST_VERSION=#{version}", "-D__DIST_PACKAGE=#{name}", "-D__DIST_ARCH=#{architecture}"]
defines = (attributes[:cpp_define] + defdef).join(" ")
::Dir.chdir(staging_path) do
opts.each do |ext|
::Dir.glob("**/*.#{ext}") do |fn|
cpp(fn, includes, defines)
end
end
end
end # def update
# apply preprocessor macros
def cpp(fn, includes, defines)
# write to temporary file
tmpfn = fn + ".i.tmp." + rand(36**10).to_s(36)
#%x[cpp -E -P -w -ansi -CC -traditional-cpp -no-integrated-cpp -nostdinc #{includes} #{defines} #{sh(fn)} -o #{sh(tmpfn)}]
r = %x[preprocess -s #{includes} #{defines} -o #{sh(tmpfn)} #{sh(fn)}]
# move back to original filename
if File.size(tmpfn) > 0
File.chmod(File.stat(fn).mode, tmpfn)
File.rename(tmpfn, fn)
end
end # def cpp
# shortcut
def sh(s)
Shellwords.escape(s)
end
end