Cross package maker. DEB/RPM generation or conversion. Derived from jordansissel/fpm.

⌈⌋ ⎇ branch:  cross package maker


Artifact [828d0ba350]

Artifact 828d0ba35074cc20518b5f104c0a35d408b01f13:

  • File lib/fpm/package/filter_preprocess.rb — part of check-in [294ea7da2a] at 2015-02-14 11:02:07 on branch trunk — Switch to preprocess.py instead of GNU CPP. (user: mario size: 3217)

#
# 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