class Autobuild::CMake

Handler class to build CMake-based packages

Constants

CMAKE_EQVS
DOXYGEN_ACCEPTED_VARIABLES

Attributes

always_use_doc_target[W]

Flag controlling whether autobuild should run doxygen itself or use the “doc” target generated by CMake

This is experimental and OFF by default. See CMake#run_doxygen for more details

See also CMake#always_use_doc_target= and CMake#always_use_doc_target? for a per-package control of that feature

full_reconfigures[W]
generator[RW]

Global default for the CMake generator to use. If nil (the default), the -G option will not be given at all. Will work only if the generator creates makefiles

It can be overriden on a per-package basis with CMake.generator=

module_path[R]
prefix_path[R]
always_reconfigure[RW]

If true, always run cmake before make during the build

always_use_doc_target[R]

Flag controlling whether autobuild should run doxygen itself or use the “doc” target generated by CMake

This is experimental and OFF by default. See CMake#run_doxygen for more details

See also CMake.always_use_doc_target= and CMake.always_use_doc_target? for a global control of that feature

defines[R]

a key => value association of defines for CMake

delete_obsolete_files_in_prefix[W]
full_reconfigures[W]

If true, we always remove the CMake cache before reconfiguring.

See full_reconfigures? for more details

generator[W]

Sets a generator explicitely for this component. See generator and CMake.generator

show_make_messages[W]

Public Class Methods

always_use_doc_target?() click to toggle source

Flag controlling whether autobuild should run doxygen itself or use the “doc” target generated by CMake

This is experimental and OFF by default. See CMake#run_doxygen for more details

See also CMake#always_use_doc_target= and CMake#always_use_doc_target? for a per-package control of that feature

# File lib/autobuild/packages/cmake.rb, line 185
def always_use_doc_target?
    @always_use_doc_target
end
builddir() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 12
def builddir
    @builddir || Configurable.builddir
end
builddir=(new) click to toggle source
# File lib/autobuild/packages/cmake.rb, line 16
def builddir=(new)
    if Pathname.new(new).absolute?
        raise ConfigException, "absolute builddirs are not supported"
    end
    if new.nil? || new.empty?
        raise ConfigException, "builddir must be non-nil and non-empty"
    end

    @builddir = new
end
define(name, value) click to toggle source
# File lib/autobuild/packages/cmake.rb, line 136
def self.define(name, value)
    @@defines[name] =
        if value.respond_to?(:to_str)
            value.to_str
        elsif value
            'ON'
        else
            'OFF'
        end
end
defines() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 132
def self.defines
    @@defines
end
delete_obsolete_files_in_prefix=(flag) click to toggle source

Set {#delete_obsolete_files_in_prefix?}

# File lib/autobuild/packages/cmake.rb, line 53
def delete_obsolete_files_in_prefix=(flag)
    @@delete_obsolete_files_in_prefix = flag
end
delete_obsolete_files_in_prefix?() click to toggle source

Whether files that are not within CMake’s install manifest but are present in the prefix should be deleted. Note that the contents of {#log_dir} are unaffected.

It is false by default. Set to true only if each package has its own prefix.

# File lib/autobuild/packages/cmake.rb, line 48
def delete_obsolete_files_in_prefix?
    @@delete_obsolete_files_in_prefix
end
full_reconfigures?() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 29
def full_reconfigures?
    @full_reconfigures
end
new(options) click to toggle source
Calls superclass method Autobuild::Configurable::new
# File lib/autobuild/packages/cmake.rb, line 115
def initialize(options)
    @defines = Hash.new
    super
    @delete_obsolete_files_in_prefix = self.class.
        delete_obsolete_files_in_prefix?
end
show_make_messages=(value) click to toggle source
# File lib/autobuild/packages/cmake.rb, line 480
def self.show_make_messages=(value)
    @show_make_messages = value
end
show_make_messages?() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 476
def self.show_make_messages?
    @show_make_messages
end

Public Instance Methods

all_defines() click to toggle source

The list of all -D options that should be passed on to CMake

# File lib/autobuild/packages/cmake.rb, line 68
def all_defines
    additional_defines = Hash[
        "CMAKE_INSTALL_PREFIX" => prefix,
        "CMAKE_MODULE_PATH" => module_path.join(";"),
        "CMAKE_PREFIX_PATH" => prefix_path.join(";")]
    self.class.defines.merge(additional_defines).merge(defines)
end
always_use_doc_target?() click to toggle source

Flag controlling whether autobuild should run doxygen itself or use the “doc” target generated by CMake

This is experimental and OFF by default. See CMake#run_doxygen for more details

See also CMake.always_use_doc_target= and CMake.always_use_doc_target? for a global control of that feature

# File lib/autobuild/packages/cmake.rb, line 209
def always_use_doc_target?
    if @always_use_doc_target.nil?
        CMake.always_use_doc_target?
    else
        @always_use_doc_target
    end
end
build() click to toggle source

Do the build in builddir

# File lib/autobuild/packages/cmake.rb, line 485
def build
    current_message = +""
    in_dir(builddir) do
        progress_start "building %s" do
            if always_reconfigure || !File.file?('Makefile')
                run('build', Autobuild.tool(:cmake), '.')
            end

            warning_count = 0
            Autobuild.make_subcommand(self, 'build') do |line|
                needs_display = false
                if line =~ /\[\s*(\d+)%\]/
                    progress "building %s (#{Integer($1)}%)"
                elsif line !~ /^(?:Generating|Linking|Scanning|Building|Built)/
                    warning_count += 1 if line =~ /warning/
                    if show_make_messages?
                        current_message += line + "\n"
                        needs_display = true
                    end
                end
                if !needs_display && !current_message.empty?
                    current_message.split("\n").each do |l|
                        message "%s: #{l}", :magenta
                    end
                    current_message.clear
                end
            end
            current_message.split("\n").each do |l|
                message "%s: #{l}", :magenta
            end
            if warning_count > 0
                msg_warning = Autoproj.color("(#{warning_count} warnings)", :bold)
                progress_done "built %s #{msg_warning}"
            else
                progress_done "built %s"
            end
        end
    end
    Autobuild.touch_stamp(buildstamp)
rescue ::Exception
    current_message.split("\n").each do |l|
        message "%s: #{l}", :magenta
    end
    raise
end
cmake_cache() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 107
def cmake_cache
    File.join(builddir, "CMakeCache.txt")
end
common_utility_handling( utility, target, *args, start_msg, done_msg, post_process: nil ) { || ... } click to toggle source
# File lib/autobuild/packages/cmake.rb, line 272
def common_utility_handling( # rubocop:disable Metrics/ParameterLists
    utility,
    target,
    *args,
    start_msg,
    done_msg,
    post_process: nil
)
    utility.source_ref_dir = builddir
    utility.task do
        progress_start start_msg, :done_message => done_msg do
            if internal_doxygen_mode?
                run_doxygen
            else
                run(utility.name,
                    Autobuild.tool(:make),
                    "-j#{parallel_build_level}",
                    target, *args,
                    working_directory: builddir)
            end
            yield if block_given?
        end

        post_process&.call
    end
end
configure() click to toggle source

Configure the builddir directory before starting make

Calls superclass method Autobuild::Configurable#configure
# File lib/autobuild/packages/cmake.rb, line 436
def configure
    super do
        in_dir(builddir) do
            unless File.file?(File.join(srcdir, 'CMakeLists.txt'))
                raise ConfigException.new(self, 'configure'),
                      "#{srcdir} contains no CMakeLists.txt file"
            end

            command = ["cmake"]

            if Autobuild.windows?
                command << '-G'
                command << "MSYS Makefiles"
            end

            all_defines.each do |name, value|
                command << "-D#{name}=#{value}"
            end
            command << Array(generator).map { |g| "-G#{g}" } if generator
            command << srcdir

            progress_start "configuring CMake for %s",
                           done_message: "configured CMake for %s" do
                FileUtils.rm_f cmake_cache if full_reconfigures?
                run('configure', *command)
            end
        end
    end
end
configurestamp() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 111
def configurestamp
    cmake_cache
end
coverage_block() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 303
def coverage_block
    proc do
        next unless test_utility.coverage_enabled?
        next unless @with_coverage

        progress_start "generating coverage report for %s",
                       done_message: "generated coverage report for %s" do
            @with_coverage.call
        end
    end
end
define(name, value) click to toggle source
# File lib/autobuild/packages/cmake.rb, line 147
def define(name, value)
    @defines[name] =
        if value.respond_to?(:to_str)
            value.to_str
        elsif value
            'ON'
        else
            'OFF'
        end
end
defines_changed?(all_defines, cache_data) click to toggle source
# File lib/autobuild/packages/cmake.rb, line 386
def defines_changed?(all_defines, cache_data)
    all_defines.any? do |name, value|
        if (match = /^#{name}:\w+=(.*)$/.match(cache_data))
            old_value = match[1]
        end

        value = value.to_s
        if !old_value || !equivalent_option_value?(old_value, value)
            if Autobuild.debug
                message "%s: option '#{name}' changed value: "\
                    "'#{old_value}' => '#{value}'"
            end

            if old_value
                message "%s: changed value of #{name} "\
                    "from #{old_value} to #{value}"
            else
                message "%s: setting value of #{name} to #{value}"
            end

            true
        end
    end
end
delete_obsolete_files() click to toggle source

@api private

Delete files in {#prefix} that are not present in CMake’s install manifest

This is enabled globally by {CMake.delete_obsolete_files_in_prefix=} or per-package with {#delete_obsolete_files_in_prefix=}. Do NOT enable if packages share the same prefix.

# File lib/autobuild/packages/cmake.rb, line 555
def delete_obsolete_files
    # The expand_path is required to sanitize the paths, which can
    # contain e.g. double //
    cmake_install_manifest = File.join(builddir, 'install_manifest.txt')
    manifest_contents = File.readlines(cmake_install_manifest).
        map { |p| File.expand_path(p.chomp) }.to_set
    logdir = self.logdir
    counter = 0
    Find.find(prefix) do |path|
        Find.prune if path == logdir
        if !manifest_contents.include?(path) && File.file?(path)
            counter += 1
            FileUtils.rm path
        end
    end
    if counter > 0
        message "%s: removed #{counter} obsolete files from prefix (cmake)"
    end
end
delete_obsolete_files_in_prefix?() click to toggle source

(see CMake.delete_obsolete_files_in_prefix?)

# File lib/autobuild/packages/cmake.rb, line 123
def delete_obsolete_files_in_prefix?
    @delete_obsolete_files_in_prefix
end
equivalent_option_value?(old, new) click to toggle source
# File lib/autobuild/packages/cmake.rb, line 337
def equivalent_option_value?(old, new)
    if old == new
        true
    else
        old = CMAKE_EQVS[old]
        new = CMAKE_EQVS[new]
        if old && new
            old == new
        else
            false
        end
    end
end
full_reconfigures?() click to toggle source

If true, we always remove the CMake cache before reconfiguring. This is to workaround the aggressive caching behaviour of CMake, and is set to true by default.

See CMake.full_reconfigures? and CMake.full_reconfigures= for a global setting

# File lib/autobuild/packages/cmake.rb, line 99
def full_reconfigures?
    if @full_reconfigures.nil?
        CMake.full_reconfigures?
    else
        @full_reconfigures
    end
end
generator() click to toggle source

The CMake generator to use. You must choose one that generates Makefiles. If not set for this package explicitely, it is using the global value CMake.generator.

# File lib/autobuild/packages/cmake.rb, line 89
def generator
    @generator || CMake.generator
end
import(**options) click to toggle source
Calls superclass method
# File lib/autobuild/packages/cmake.rb, line 351
def import(**options)
    super

    Dir.glob(File.join(srcdir, "*.pc.in")) do |file|
        file = File.basename(file, ".pc.in")
        provides "pkgconfig/#{file}"
    end
end
install() click to toggle source

Install the result in prefix

If {#delete_obsolete_files_in_prefix?} is set, files that are present in the prefix but not in CMake’s install manifest will be removed.

Calls superclass method
# File lib/autobuild/packages/cmake.rb, line 535
def install
    in_dir(builddir) do
        progress_start "installing %s", done_message: 'installed %s' do
            run('install', Autobuild.tool(:make),
                "-j#{parallel_build_level}", 'install')
        end

        delete_obsolete_files if delete_obsolete_files_in_prefix?
    end
    super
end
internal_doxygen_mode?() click to toggle source

To avoid having to build packages to run the documentation target, we try to autodetect whether (1) the package is using doxygen and (2) whether the cmake variables in the doxyfile can be provided by autobuild itself.

This can be disabled globally by setting Autobuild::CMake.always_use_doc_target= or on a per-package basis with always_use_doc_target=

This method returns true if the package can use the internal doxygen mode and false otherwise

# File lib/autobuild/packages/cmake.rb, line 228
def internal_doxygen_mode?
    return false if always_use_doc_target?

    doxyfile_in = File.join(srcdir, "Doxyfile.in")
    return false unless File.file?(doxyfile_in)

    File.readlines(doxyfile_in).each do |line|
        matches = line.scan(/@[^@]+@/)
        if matches.any? { |str| !DOXYGEN_ACCEPTED_VARIABLES.key?(str) }
            return false
        end
    end
end
module_path() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 360
def module_path
    CMake.module_path
end
prefix_path() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 364
def prefix_path
    seen = Set.new
    result = Array.new

    raw = (dependencies.map { |pkg_name| Autobuild::Package[pkg_name].prefix } +
        CMake.prefix_path)
    raw.each do |path|
        unless seen.include?(path)
            seen << path
            result << path
        end
    end
    result
end
prepare() click to toggle source
Calls superclass method Autobuild::Configurable#prepare
# File lib/autobuild/packages/cmake.rb, line 411
def prepare
    # A failed initial CMake configuration leaves a CMakeCache.txt file,
    # but no Makefile.
    #
    # Delete the CMakeCache to force reconfiguration
    unless File.exist?(File.join(builddir, 'Makefile'))
        FileUtils.rm_f(cmake_cache)
    end

    doc_utility.source_ref_dir = builddir

    if File.exist?(cmake_cache)
        cache = File.read(cmake_cache)
        if defines_changed?(all_defines, cache)
            if Autobuild.debug
                message "%s: CMake configuration changed, forcing a reconfigure"
            end
            FileUtils.rm_f cmake_cache
        end
    end

    super
end
run_doxygen() click to toggle source

To avoid having to build packages to run the documentation target, we try to autodetect whether (1) the package is using doxygen and (2) whether the cmake variables in the doxyfile can be provided by autobuild itself.

This can be disabled globally by setting Autobuild::CMake.always_use_doc_target or on a per-package basis with always_use_doc_target

This method generates the corresponding doxygen file in <builddir>/Doxygen and runs doxygen. It raises if the internal doxygen support cannot be used on this package

# File lib/autobuild/packages/cmake.rb, line 254
def run_doxygen
    doxyfile_in = File.join(srcdir, "Doxyfile.in")
    unless File.file?(doxyfile_in)
        raise "no Doxyfile.in in this package, "\
            "cannot use the internal doxygen support"
    end
    doxyfile_data = File.readlines(doxyfile_in).map do |line|
        line.gsub(/@[^@]+@/) do |match|
            DOXYGEN_ACCEPTED_VARIABLES[match].call(self)
        end
    end
    doxyfile = File.join(builddir, "Doxyfile")
    File.open(doxyfile, 'w') do |io|
        io.write(doxyfile_data)
    end
    run('doc', Autobuild.tool(:doxygen), doxyfile)
end
self_fingerprint() click to toggle source
Calls superclass method
# File lib/autobuild/packages/cmake.rb, line 575
def self_fingerprint
    return unless (base = super)

    all_defines = self.class.defines.merge(defines).sort_by(&:first)
    Digest::SHA1.hexdigest(base + all_defines.join(""))
end
show_make_messages?() click to toggle source
# File lib/autobuild/packages/cmake.rb, line 466
def show_make_messages?
    if !@show_make_messages.nil?
        @show_make_messages
    else
        CMake.show_make_messages?
    end
end
update_environment() click to toggle source
Calls superclass method
# File lib/autobuild/packages/cmake.rb, line 379
def update_environment
    super
    prefix_path.each do |p|
        env_add_path 'CMAKE_PREFIX_PATH', p
    end
end
with_coverage(&block) click to toggle source
# File lib/autobuild/packages/cmake.rb, line 299
def with_coverage(&block)
    @with_coverage ||= block
end
with_doc(target = 'doc', &block) click to toggle source

Declare that the given target can be used to generate documentation

# File lib/autobuild/packages/cmake.rb, line 316
def with_doc(target = 'doc', &block)
    common_utility_handling(
        doc_utility, target,
        "generating documentation for %s",
        "generated documentation for %s", &block)
end
with_tests(target = 'test', &block) click to toggle source
# File lib/autobuild/packages/cmake.rb, line 323
def with_tests(target = 'test', &block)
    common_utility_handling(
        test_utility, target, "ARGS=-V",
        "running tests for %s",
        "successfully ran tests for %s",
        post_process: coverage_block, &block)
end