module RBuildSys

Namespace for all code for RBuildSys

Constants

CONFIG_SYMBOLS

Stores all global symbols to configure files

DECLARED_PROJECTS
OPTIONS

Stores all options; will be modified through the commandline option parser @see @@optparse

PROJECTS

Stores all projects that are defined by the user

TOOLCHAINS

Stores all currently loaded toolchains

Private Class Methods

loadToolchain(file) click to toggle source

Loads a toolchain definition from a file. Format needs to be JSON.

@param file [String] path to the toolchain definition file

# File lib/rbuildsys.rb, line 984
def self.loadToolchain(file)
    if (!File.exists?(file)) then
        raise ArgumentError.new("Argument #1 (file) needs to be the path to an existing file");
    end

    data = JSON.parse(File.read(file));
    if (TOOLCHAINS.keys.include?(data["name"])) then
        raise RuntimeError.new("Cannot load toolchain '#{data["name"]}' from '#{file}': already loaded");
    end
    TOOLCHAINS[data["name"]] = data;

    return data;
end
load_default_toolchains() click to toggle source
# File lib/rbuildsys.rb, line 999
def self.load_default_toolchains
    # load builtin toolchains
    gemDir = File.dirname(File.expand_path(__FILE__));
    toolchains = Dir.glob("#{gemDir}/toolchains/*.json");
    toolchains.each {|f|
        self.loadToolchain(f);
    }

    # use toolchain installed for the user
    toolchains = Dir.glob("#{Dir.home}/.rbuildsys/toolchains/*.json");
    toolchains.each {|f|
        self.loadToolchain(f);
    }
end

Public Instance Methods

configureFile(input, output, options = {}) click to toggle source

Tells the project that, in order to build it, the file specified at input must be transformed to the file at output.

@note Should only be called inside the block for {#newProject} @param input [String] The filename of the file that should be configured @param output [String] The filename that should be used to save the result, cannot be the same as the input! @param options [Hash] Some optional options

# File lib/rbuildsys.rb, line 1039
def configureFile(input, output, options = {})
    if (!input.is_a?(String) || input.strip.empty?) then
        raise ArgumentError.new("Argument #1 (input) needs to be a string");
    end
    
    if (!output.is_a?(String) || output.strip.empty?) then
        raise ArgumentError.new("Argument #2 (output) needs to be a string");
    end

    if (input == output) then
        raise ArgumentError.new("Argument #1 (input) and #2 (output) cannot be the same");
    end

    @@cur_proj.config_files.push({
        input: File.join(@@cur_proj.baseDir, input),
        output: File.join(@@cur_proj.baseDir, output),
        options: options
    });
end
isLinux?() click to toggle source

Shorthand for {Project#isMac?}

# File lib/rbuildsys.rb, line 1074
def isLinux?()
    return @@cur_proj.isLinux?;
end
isMac?() click to toggle source

Shorthand for {Project#isMac?}

# File lib/rbuildsys.rb, line 1069
def isMac?()
    return @@cur_proj.isMac?;
end
isToolchainOS?(type) click to toggle source

Tests if the toolchain is the given type of OS.

@param type [:win, :win32, :windows, :mac, :macos, :apple, :linux] the OS to check @return [Boolean] Returns true if OS is correct, false otherwise

# File lib/rbuildsys.rb, line 1082
def isToolchainOS?(type)
    if ([:win, :win32, :windows].include?(type)) then
        return @@cur_proj.isWindows?;
    end

    if ([:mac, :macos, :apple].include?(type)) then
        return @@cur_proj.isMac?();
    end

    if ([:linux].include?(type)) then
        return @@cur_proj.isLinux?();
    end

    raise ArgumentError.new("Unexpected argument: os-type '#{type}' unknown");
end
isWindows?() click to toggle source

Shorthand for {Project#isWindows?}

# File lib/rbuildsys.rb, line 1064
def isWindows?()
    return @@cur_proj.isWindows?;
end
set(symbol, value = nil) click to toggle source

Sets a symbol with an optional value to configure files. See {#configureFile}

@note When used inside the block for {#newProject}, the symbol is only visible for the project. If used outside of the block, the symbol is visible for everyone! @param symbol [String] The symbol that should be set @param value [String, nil] Optional value for the symbol

# File lib/rbuildsys.rb, line 1025
def set(symbol, value = nil)
    if (@@cur_proj == nil) then
        CONFIG_SYMBOLS[symbol] = value;
    else
        @@cur_proj.config_symbols[symbol] = value;
    end
end

Private Instance Methods

build() click to toggle source

Begins the build process. Should be called after you configured all your projects with {#newProject}.

# File lib/rbuildsys.rb, line 693
def build()
    parseARGV();
    ARGV.each { |projname|
        proj = PROJECTS[projname];
        if (proj) then
            if (OPTIONS[:clean]) then
                proj.clean();
            elsif (OPTIONS[:install]) then
                proj.install();
            else
                proj.build();
            end
        end
    }
end
checkSysVersion(min_version) click to toggle source

Checks if this RBuildSys is at minimum the required version. This is only for scripts that dont use systems like bundler etc. If you use bundler or similar dependency management software, you propably should use their features instead of this. @return [Boolean]

# File lib/rbuildsys.rb, line 734
def checkSysVersion(min_version)
    data_min = min_version.split(".");
    data_ver = sysVersion().split(".");
    
    if (data_ver.size != data_min.size) then
        return false;
    end
    if (data_ver.size == 4 && data_ver[3] != data_min[3]) then
        # 4th part dosnt match. Should be something like 'pre' or similar.
        return false;
    end

    data_min.pop();
    data_ver.pop();

    while (data_ver.size > 0) do
        a = data_min.pop();
        b = data_ver.pop();
        return false if (a > b);
    end

    return true;
end
declareProjects(*projects) click to toggle source

Declares the project's name so they can be displayed in the help text!

# File lib/rbuildsys.rb, line 720
def declareProjects(*projects)
    DECLARED_PROJECTS.push(*projects);
end
define(symbol, value = nil) click to toggle source

Adds a define to the compiler call

@note Should only be called inside the block for {#newProject} @param symbol [String] Symbol that should be defined @param value [String, nil] Optional value the symbol should hold

# File lib/rbuildsys.rb, line 942
def define(symbol, value = nil)
    @@cur_proj.defines[symbol] = value;
end
flag(flag) click to toggle source

Adds a flag to the flags of the current project.

@note Should only be called inside the block for {#newProject} @note This should only be used when nothing else works, because this method dosnt ensure that the flags used are working with the current toolchain! @param flag [String] the flag to be added

# File lib/rbuildsys.rb, line 951
def flag(flag)
    @@cur_proj.flags.push(flag);
end
getInstallPath() click to toggle source

Returns the install path for the current project

@note Should only be called inside the block for {#newProject}

# File lib/rbuildsys.rb, line 858
def getInstallPath()
    dir = OPTIONS[:installDir] || "/usr/include" if (isLinux? || isMac?);
    dir = OPTIONS[:installDir] || "C:/Program Files/#{@@cur_proj.outputName}" if (isWindows?);
    return File.expand_path(dir);
end
incDir(dir, *more) click to toggle source

Adds include directorys to use for the current project

@note Should only be called inside the block for {#newProject} @param dir [String, Array<String>] Directory path; root of the include path. If its a Array, each element is used in a call to {#incDir} @param more [Array<String>] Additional include paths; each element is used in a call to {#incDir}

# File lib/rbuildsys.rb, line 767
def incDir(dir, *more)
    if (dir.class == String) then
        dirPath = File.join(@@cur_proj.baseDir, dir);
        raise ArgumentError.new("Argument #1 is no directory: '#{dir}' ('#{dirPath}')") if (!Dir.exists?(dirPath));
        @@cur_proj.inc_dirs.push(dirPath);
    elsif (dir.class == Array) then
        dir.each { |d| incDir(d) }
    else
        raise ArgumentError.new("Argument #1 must be a String or an Array");
    end
    more.each { |d| incDir(d) }
end
isLib(type) click to toggle source

Sets the current project as a lib

@note Should only be called inside the block for {#newProject} @param type [:static, :dynamic, :s, :dyn, :both] The type of the library: static (*.a / *.lib) or dynamic (*.so / *.dll)

# File lib/rbuildsys.rb, line 848
def isLib(type)
    @@cur_proj.libType = :static if ([:static, :s].include?(type));
    @@cur_proj.libType = :dynamic if ([:dynamic, :dyn, :d].include?(type));
    @@cur_proj.libType = :both if (type == :both);
    raise ArgumentError.new("Argument #1 (type) must be one of the following: :static, :dynamic, :s, :dyn, :both") if (@@cur_proj.libType == nil)
end
newProject(name, options = {}) { || ... } click to toggle source

Creates a new project to build. Takes a block to execute, that defines the project. The block is immediately executed, and has access to the current project (that is created with this method) in {RBuildSys::@@cur_proj RBuildSys::@@cur_proj}.

@yield Block to configure the project

@param name [String] Name of the project, also used for the final output of the project @param options [Hash] Various options; for details see {Project#initialize}

# File lib/rbuildsys.rb, line 681
def newProject(name, options = {})
    raise ArgumentError.new("Argument #1 (name) need to be a string") if (name.class != String);
    raise ArgumentError.new("Argument #2 (options) need to be an hash") if (!options.is_a?(Hash));

    @@cur_proj = Project.new(name, options);
    yield
    PROJECTS[name] = @@cur_proj;
    @@cur_proj = nil;
end
noInstall() click to toggle source

Tells the current project that it is not install-able This means that if you run an install of your projects, this one will not be installed

@note Should only be called inside the block for {#newProject}

# File lib/rbuildsys.rb, line 840
def noInstall()
    @@cur_proj.no_install = true;
end
onHeadOption(*opts, &block) click to toggle source

Adds an option to the option parser of RBuildSys @see OptionParser#on_head

# File lib/rbuildsys.rb, line 973
def onHeadOption(*opts, &block)
    @@optparse.on_head(*opts, block);
end
onOption(*opts, &block) click to toggle source

Adds an option to the option parser of RBuildSys @see OptionParser#on

# File lib/rbuildsys.rb, line 961
def onOption(*opts, &block)
    @@optparse.on(*opts, block);
end
onTailOption(*opts, &block) click to toggle source

Adds an option to the option parser of RBuildSys @see OptionParser#on_tail

# File lib/rbuildsys.rb, line 967
def onTailOption(*opts, &block)
    @@optparse.on_tail(*opts, block);
end
parseARGV() click to toggle source

Parses the commandline arguments @note this should be called before any call to {#newProject} and/or {#build}!

# File lib/rbuildsys.rb, line 711
def parseARGV()
    @@optparse.parse!
    if (ARGV.length == 0) then
        puts @@optparse;
        exit(1);
    end
end
publish_incDir(dir, *more) click to toggle source

Adds include directorys to use for projects that depends on the current project

@note Should only be called inside the block for {#newProject} @param dir [String, Array<String>] Directory path; root of the include path. If its a Array, each element is used in a call to {#publish_incDir} @param more [Array<String>] Additional include paths; each element is used in a call to {#publish_incDir}

# File lib/rbuildsys.rb, line 785
def publish_incDir(dir, *more)
    if (@@cur_proj.libType == nil) then
        raise RuntimeError.new("Can only be called when the project is configured as an library");
    end

    if (dir.class == String) then
        dirPath = File.join(@@cur_proj.baseDir, dir);
        raise ArgumentError.new("Argument #1 is no directory: '#{dir}' ('#{dirPath}')") if (!Dir.exists?(dirPath));
        @@cur_proj.public_inc_dirs.push(dirPath);
    elsif (dir.class == Array) then
        dir.each { |d| publish_incDir(d) }
    else
        raise ArgumentError.new("Argument #1 must be a String or an Array");
    end
    more.each { |d| publish_incDir(d) }
end
srcDir(dir, *more) click to toggle source

Adds source directorys to use for the current project

@note Should only be called inside the block for {#newProject} @param dir [String, Array<String>] Directory path; root of the source path. If its a Array, each element is used in a call to {#srcDir} @param more [Array<String>] Additional source paths; each element is used in a call to {#srcDir}

# File lib/rbuildsys.rb, line 807
def srcDir(dir, *more)
    if (dir.class == String) then
        dirPath = File.join(@@cur_proj.baseDir, dir);
        raise ArgumentError.new("Argument #1 is no directory: '#{dir}' ('#{dirPath}')") if (!Dir.exists?(dirPath));
        @@cur_proj.src_dirs.push(dirPath);
    elsif (dir.class == Array) then
        dir.each { |d| srcDir(d) }
    else
        raise ArgumentError.new("Argument #1 must be a String or an Array");
    end
    more.each { |d| srcDir(d) }
end
srcGlob(glob, *more) click to toggle source

Adds a source glob to use for the current project

@note Should only be called inside the block for {#newProject} @param glob [String, Array<String>] Glob to be used to find source files; If its a Array, each element is used in a call to {#srcGlob} @param more [Array<String>] Additional source globs; each element is used in a call to {#srcGlob}

# File lib/rbuildsys.rb, line 825
def srcGlob(glob, *more)
    if (glob.class == String) then
        @@cur_proj.src_globs.push(File.join(@@cur_proj.baseDir, glob));
    elsif (glob.class == Array) then
        glob.each { |g| srcGlob(g) }
    else
        raise ArgumentError.new("Argument #1 must be a String or an Array");
    end
    more.each { |g| srcGlob(g) }
end
sysVersion() click to toggle source

Returns the version of RBuildSys @return [β€œ1.0.0”]

# File lib/rbuildsys.rb, line 726
def sysVersion()
    return "1.0.0";
end
use(name, linktype) click to toggle source

Links a RBuildSys project to the current project. This has the effect that the given project is build before the current project, and if the given project is a lib, it is also linked to the current project

@note Should only be called inside the block for {#newProject} @param name [String] Can be a local project (inside current file) or any installed project @param linktype [:static, :dynamic] Specify wich linkage type should be used to link the project with the current one.

If the project to link dosnt support the linktype, this raises an error.
# File lib/rbuildsys.rb, line 872
def use(name, linktype)
    if (PROJECTS[name] == nil) then
        @@cur_proj.dependencys.push([name, linktype]);
    else
        # use local
        proj = PROJECTS[name];

        if (!proj.libType) then
            raise ArgumentError.new("Argument #1 can't be used cause it is not a library");
        end
        if (proj.libType != linktype && proj.libType != :both) then
            raise ArgumentError.new("Argument #1 can't be linked with linktype #{linktype}!");
        end

        @@cur_proj.dependencys.push(proj);
    end
end
useLib(name, path = nil, options = {}) click to toggle source

Adds a external library to the current project

@note Should only be called inside the block for {#newProject} @note There is currently no check in place to verify that the given library exists @param name [String] Name of the library that should be used. in a c/c++ context, it should be without the leading β€œlib” @param path [String, nil] Optional search path for this library @param options [Hash] Optional options @option options :pkgconf [Boolean] If true, search pkgconf(ig) for additional informations about the lib

# File lib/rbuildsys.rb, line 927
def useLib(name, path = nil, options = {})
    if (options[:pkgconf]) then
        usePkgconf(name);
        return;
    end

    @@cur_proj.librarys.push(name);
    @@cur_proj.lib_dirs.push(path) if (path != nil && Dir.exists?(path));
end
usePkgconf(name) click to toggle source

Adds a external library through pkg-config. If no pkg-config is installed on the system, this functions raises an error

@note Should only be called inside the block for {#newProject} @note For retriving the flags from pkg-config, --libs and --cflags is used, and the output is given to {#flag} @param name [String] Name of the pkg-config package

# File lib/rbuildsys.rb, line 896
def usePkgconf(name)
    if (`which pkg-config` == "") then
        raise ArgumentError.new("Option pkgconf specified, but no pkg-config installed on system!");
    end

    modver = `pkg-config --short-errors --modversion #{name}`;
    if (modver.start_with?("No package") or $?.exitstatus != 0) then
        raise RuntimeError.new("Could not find package '#{name}' with pkg-config!");
    end

    linker_flags = `pkg-config --short-errors --libs #{name}`;
    if ($?.exitstatus != 0) then
        raise RuntimeError.new("Could not get linkler flags for '#{name}', plg-config error: #{linker_flags}");
    end
    flag(linker_flags);

    cflags = `pkg-config --short-errors --cflags #{name}`;
    if ($?.exitstatus != 0) then
        raise RuntimeError.new("Could not get compiler flags for '#{name}', plg-config error: #{linker_flags}");
    end
    flag(cflags);
end