mtbuild 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.md +27 -0
- data/README.md +528 -0
- data/bin/mtbuild +10 -0
- data/lib/mtbuild.rb +13 -0
- data/lib/mtbuild/application.rb +39 -0
- data/lib/mtbuild/application_configuration.rb +38 -0
- data/lib/mtbuild/application_project.rb +21 -0
- data/lib/mtbuild/application_task.rb +23 -0
- data/lib/mtbuild/compiled_configuration.rb +73 -0
- data/lib/mtbuild/configuration.rb +46 -0
- data/lib/mtbuild/dsl.rb +46 -0
- data/lib/mtbuild/mtbuild.rb +10 -0
- data/lib/mtbuild/project.rb +71 -0
- data/lib/mtbuild/staticlibrary_configuration.rb +49 -0
- data/lib/mtbuild/staticlibrary_project.rb +21 -0
- data/lib/mtbuild/staticlibrary_task.rb +31 -0
- data/lib/mtbuild/test_application_configuration.rb +33 -0
- data/lib/mtbuild/test_application_project.rb +22 -0
- data/lib/mtbuild/test_application_task.rb +23 -0
- data/lib/mtbuild/toolchain.rb +109 -0
- data/lib/mtbuild/toolchains/arm_none_eabi_gcc.rb +69 -0
- data/lib/mtbuild/toolchains/gcc.rb +160 -0
- data/lib/mtbuild/utils.rb +46 -0
- data/lib/mtbuild/version.rb +4 -0
- data/lib/mtbuild/versioner.rb +54 -0
- data/lib/mtbuild/versioners/mt_std_version.rb +72 -0
- data/lib/mtbuild/workspace.rb +112 -0
- metadata +153 -0
data/bin/mtbuild
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
lib_path_expanded = File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
|
|
4
|
+
if File.directory?(lib_path_expanded)
|
|
5
|
+
$:.unshift(lib_path_expanded) unless $:.include?(lib_path_expanded)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'mtbuild'
|
|
9
|
+
|
|
10
|
+
Rake.application.run
|
data/lib/mtbuild.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
|
|
3
|
+
require "mtbuild/application"
|
|
4
|
+
require "mtbuild/application_project"
|
|
5
|
+
require "mtbuild/application_task"
|
|
6
|
+
require "mtbuild/dsl"
|
|
7
|
+
require "mtbuild/mtbuild"
|
|
8
|
+
require "mtbuild/staticlibrary_project"
|
|
9
|
+
require "mtbuild/staticlibrary_task"
|
|
10
|
+
require "mtbuild/test_application_project"
|
|
11
|
+
require "mtbuild/test_application_task"
|
|
12
|
+
require "mtbuild/version"
|
|
13
|
+
require "mtbuild/workspace"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Rake
|
|
2
|
+
class << self
|
|
3
|
+
# Singleton MTBuild application instance
|
|
4
|
+
def application
|
|
5
|
+
@application ||= MTBuild::Application.new
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module MTBuild
|
|
11
|
+
|
|
12
|
+
require 'rake'
|
|
13
|
+
|
|
14
|
+
# This subclasses the Rake::Application class only only to inject the MTBuild
|
|
15
|
+
# version number for display when mtbuild is invoked with the --version flag.
|
|
16
|
+
class Application < Rake::Application
|
|
17
|
+
|
|
18
|
+
# This hijacks the "--version" flag and displays the MTBuild version along
|
|
19
|
+
# with the Rake version. All other options/flags are returned unmodified.
|
|
20
|
+
def standard_rake_options
|
|
21
|
+
return super.map do |opt|
|
|
22
|
+
if opt.first == '--version'
|
|
23
|
+
['--version', '-V',
|
|
24
|
+
"Display the program version.",
|
|
25
|
+
lambda { |value|
|
|
26
|
+
puts "mtbuild, version #{MTBuild::VERSION}"
|
|
27
|
+
puts "rake, version #{RAKEVERSION}"
|
|
28
|
+
exit
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
else
|
|
32
|
+
opt
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module MTBuild
|
|
2
|
+
require 'mtbuild/compiled_configuration'
|
|
3
|
+
|
|
4
|
+
# Use this class to create application configurations. You won't typically
|
|
5
|
+
# instantiate this directly. Instead, the ApplicationProject.add_configuration
|
|
6
|
+
# method will create this for you.
|
|
7
|
+
class ApplicationConfiguration < CompiledConfiguration
|
|
8
|
+
|
|
9
|
+
# Create the actual Rake tasks that will perform the configuration's work
|
|
10
|
+
def configure_tasks
|
|
11
|
+
super
|
|
12
|
+
all_object_files = []
|
|
13
|
+
all_object_folders = []
|
|
14
|
+
@toolchains.each do |toolchain, sources|
|
|
15
|
+
object_files, object_folders = toolchain.create_compile_tasks(sources)
|
|
16
|
+
all_object_files |= object_files
|
|
17
|
+
all_object_folders |= object_folders
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
application_binaries, application_files, application_folders = @default_toolchain.create_application_tasks(all_object_files, @project_name)
|
|
21
|
+
dependencies = @dependencies+all_object_folders+application_folders+application_files+application_binaries
|
|
22
|
+
|
|
23
|
+
desc "Build application '#{@project_name}' with configuration '#{@configuration_name}'"
|
|
24
|
+
new_task = application_task @configuration_name => dependencies do |t|
|
|
25
|
+
puts "built application #{t.name}."
|
|
26
|
+
@tests.each do |test|
|
|
27
|
+
if Rake::Task.task_defined? test
|
|
28
|
+
Rake::Task[test].invoke
|
|
29
|
+
else
|
|
30
|
+
$stderr.puts "warning: Skipping unknown test '#{test}'"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module MTBuild
|
|
2
|
+
require "mtbuild/application_configuration"
|
|
3
|
+
require 'mtbuild/project'
|
|
4
|
+
|
|
5
|
+
# This class is used to build applications. An application has compilation
|
|
6
|
+
# and link phases that produce a binary executable.
|
|
7
|
+
class ApplicationProject < Project
|
|
8
|
+
|
|
9
|
+
# Adds a named ApplicationConfiguration to the project.
|
|
10
|
+
def add_configuration(configuration_name, configuration)
|
|
11
|
+
super
|
|
12
|
+
default_configuration = Workspace.configuration_defaults.fetch(configuration_name, {})
|
|
13
|
+
merged_configuration = Utils.merge_configurations(default_configuration, configuration)
|
|
14
|
+
cfg = ApplicationConfiguration.new(@project_name, @project_folder, effective_output_folder, configuration_name, merged_configuration)
|
|
15
|
+
@configurations << cfg
|
|
16
|
+
return cfg
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Rake
|
|
2
|
+
|
|
3
|
+
require 'rake'
|
|
4
|
+
|
|
5
|
+
# This is a top-level Rake task for creating an application
|
|
6
|
+
class ApplicationTask < Task
|
|
7
|
+
|
|
8
|
+
def initialize(task_name, app)
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module DSL
|
|
15
|
+
|
|
16
|
+
# DSL method to create an application task.
|
|
17
|
+
def application_task(*args, &block)
|
|
18
|
+
new_task = Rake::ApplicationTask.define_task(*args, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module MTBuild
|
|
2
|
+
require 'mtbuild/configuration'
|
|
3
|
+
require 'mtbuild/toolchain'
|
|
4
|
+
|
|
5
|
+
# This is the base class for configurations representing compiled objects
|
|
6
|
+
# (libraries, applications, etc.)
|
|
7
|
+
class CompiledConfiguration < Configuration
|
|
8
|
+
|
|
9
|
+
# A list of Rake tasks that this configuration depends upon
|
|
10
|
+
attr_reader :dependencies
|
|
11
|
+
|
|
12
|
+
# A list of source files that will be compiled
|
|
13
|
+
attr_reader :source_files
|
|
14
|
+
|
|
15
|
+
# A list of Rake test tasks that will execute after this configuration builds
|
|
16
|
+
attr_reader :tests
|
|
17
|
+
|
|
18
|
+
def initialize(project_name, project_folder, output_folder, configuration_name, configuration)
|
|
19
|
+
super
|
|
20
|
+
check_configuration(configuration)
|
|
21
|
+
|
|
22
|
+
@dependencies = configuration.fetch(:dependencies, [])
|
|
23
|
+
@default_toolchain_config = configuration[:toolchain]
|
|
24
|
+
@default_toolchain = Toolchain.create_toolchain(@default_toolchain_config)
|
|
25
|
+
|
|
26
|
+
source_files = Utils.expand_file_list(configuration.fetch(:sources, []), configuration.fetch(:excludes, []), @project_folder)
|
|
27
|
+
@toolchains = {@default_toolchain => source_files}
|
|
28
|
+
|
|
29
|
+
@tests = Utils.ensure_array(configuration.fetch(:tests, []))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# This method adds source files with their own toolchains. Use this method
|
|
33
|
+
# to add any source files that need special toolchain settings.
|
|
34
|
+
def add_sources(sources, excludes=[], toolchain_configuration)
|
|
35
|
+
merged_configuration = Utils.merge_configurations(@default_toolchain_config, toolchain_configuration)
|
|
36
|
+
toolchain = Toolchain.create_toolchain(merged_configuration)
|
|
37
|
+
@toolchains[toolchain] = Utils.expand_file_list(sources, excludes, @project_folder)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Create the actual Rake tasks that will perform the configuration's work
|
|
41
|
+
def configure_tasks
|
|
42
|
+
super
|
|
43
|
+
@toolchains.each do |toolchain, sources|
|
|
44
|
+
toolchain.output_folder = @output_folder
|
|
45
|
+
toolchain.project_folder = @project_folder
|
|
46
|
+
toolchain.output_decorator = "-#{@configuration_name}"
|
|
47
|
+
CompiledConfiguration.add_framework_dependencies_to_toolchain(toolchain, @dependencies)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def check_configuration(configuration)
|
|
54
|
+
fail "No toolchain specified for #{@project_name}:#{@configuration_name}" if configuration.fetch(:toolchain, nil).nil?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.add_framework_dependencies_to_toolchain(toolchain, *dependencies)
|
|
58
|
+
dependencies.each do |dependency|
|
|
59
|
+
if dependency.respond_to? :to_ary
|
|
60
|
+
CompiledConfiguration.add_framework_dependencies_to_toolchain(toolchain, *dependency.to_ary)
|
|
61
|
+
else
|
|
62
|
+
task_dependency = Rake.application.lookup(dependency)
|
|
63
|
+
fail "Unable to locate task for dependency: #{dependency}" if task_dependency.nil?
|
|
64
|
+
toolchain.add_include_paths(task_dependency.api_headers) if task_dependency.respond_to? :api_headers
|
|
65
|
+
toolchain.add_include_objects(task_dependency.library_files) if task_dependency.respond_to? :library_files
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
include Rake::DSL
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module MTBuild
|
|
2
|
+
|
|
3
|
+
require 'mtbuild/versioner'
|
|
4
|
+
|
|
5
|
+
# This is the base class for all configuration types.
|
|
6
|
+
class Configuration
|
|
7
|
+
|
|
8
|
+
# The configuration's name
|
|
9
|
+
attr_reader :configuration_name
|
|
10
|
+
|
|
11
|
+
# The name of the project that owns this configuration
|
|
12
|
+
attr_reader :project_name
|
|
13
|
+
|
|
14
|
+
# The project's folder. Relative path references are interpreted as
|
|
15
|
+
# relative to this folder.
|
|
16
|
+
attr_reader :project_folder
|
|
17
|
+
|
|
18
|
+
# The project's output folder. Project output goes here.
|
|
19
|
+
attr_reader :output_folder
|
|
20
|
+
|
|
21
|
+
def initialize(project_name, project_folder, output_folder, configuration_name, configuration)
|
|
22
|
+
check_configuration(configuration)
|
|
23
|
+
@project_name = project_name
|
|
24
|
+
@project_folder = File.expand_path(project_folder)
|
|
25
|
+
@configuration_name = configuration_name
|
|
26
|
+
@output_folder = File.expand_path(File.join(output_folder, @project_name.to_s, @configuration_name.to_s))
|
|
27
|
+
|
|
28
|
+
@versioner = nil
|
|
29
|
+
@versioner_config = configuration.fetch(:versioner, nil)
|
|
30
|
+
@versioner = Versioner.create_versioner(@project_name, @project_folder, @output_folder, @configuration_name, @versioner_config) unless @versioner_config.nil?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Create the actual Rake tasks that will perform the configuration's work
|
|
34
|
+
def configure_tasks
|
|
35
|
+
@versioner.create_version_tasks unless @versioner.nil?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def check_configuration(configuration)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
include Rake::DSL
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
data/lib/mtbuild/dsl.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module MTBuild
|
|
2
|
+
|
|
3
|
+
module DSL
|
|
4
|
+
|
|
5
|
+
# Defines a Workspace
|
|
6
|
+
def workspace(workspace_name, workspace_folder, &configuration_block)
|
|
7
|
+
MTBuild::Workspace.new(workspace_name, workspace_folder, &configuration_block)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Defines an ApplicationProject
|
|
11
|
+
def application_project(application_name, project_folder, &configuration_block)
|
|
12
|
+
MTBuild::ApplicationProject.new(application_name, project_folder, &configuration_block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Defines a StaticLibraryProject
|
|
16
|
+
def static_library_project(library_name, project_folder, &configuration_block)
|
|
17
|
+
MTBuild::StaticLibraryProject.new(library_name, project_folder, &configuration_block)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Defines a TestApplicationProject
|
|
21
|
+
def test_application_project(application_name, project_folder, &configuration_block)
|
|
22
|
+
MTBuild::TestApplicationProject.new(application_name, project_folder, &configuration_block)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Defines a Toolchain
|
|
26
|
+
def toolchain(toolchain_name, toolchain_configuration={})
|
|
27
|
+
fail "error: the toolchain configuration is expected to be a hash." unless toolchain_configuration.is_a? Hash
|
|
28
|
+
toolchain_configuration[:name] = toolchain_name
|
|
29
|
+
return toolchain_configuration
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Defines a Versioner
|
|
33
|
+
def versioner(versioner_name, versioner_configuration={})
|
|
34
|
+
fail "error: the version file configuration is expected to be a hash." unless versioner_configuration.is_a? Hash
|
|
35
|
+
versioner_configuration[:name] = versioner_name
|
|
36
|
+
return versioner_configuration
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Extend the main object with the DSL commands. This allows top-level calls to
|
|
44
|
+
# workspace, application_project, etc. to work from a Rakefile without
|
|
45
|
+
# polluting the object inheritance tree.
|
|
46
|
+
self.extend MTBuild::DSL
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module MTBuild
|
|
2
|
+
|
|
3
|
+
# This is the base class for all project types.
|
|
4
|
+
class Project
|
|
5
|
+
|
|
6
|
+
# The project's name
|
|
7
|
+
attr_reader :project_name
|
|
8
|
+
|
|
9
|
+
# The project's folder. Relative path references are interpreted as
|
|
10
|
+
# relative to this folder.
|
|
11
|
+
attr_reader :project_folder
|
|
12
|
+
|
|
13
|
+
# The project's output folder. Project output goes here.
|
|
14
|
+
attr_reader :output_folder
|
|
15
|
+
|
|
16
|
+
# If supplied, the configuration_block will be passed the
|
|
17
|
+
# newly-constructed Project object.
|
|
18
|
+
def initialize(project_name, project_folder, &configuration_block)
|
|
19
|
+
@configurations = []
|
|
20
|
+
@default_tasks = []
|
|
21
|
+
@project_name = project_name
|
|
22
|
+
@project_folder = File.expand_path(project_folder)
|
|
23
|
+
@output_folder = File.expand_path(File.join(@project_folder, MTBuild.default_output_folder))
|
|
24
|
+
configuration_block.call(self) if configuration_block
|
|
25
|
+
|
|
26
|
+
namespace @project_name do
|
|
27
|
+
@configurations.each do |configuration|
|
|
28
|
+
configuration.configure_tasks()
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# If there is no active workspace, set up any registered default project tasks
|
|
33
|
+
task :default => @default_tasks unless Workspace.have_workspace?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Add tasks to be built by default if MTBuild is invoked with no arguments
|
|
37
|
+
def add_default_tasks(default_tasks)
|
|
38
|
+
@default_tasks |= Utils.ensure_array(default_tasks).flatten
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Set the project's output folder.
|
|
42
|
+
def set_output_folder(output_folder)
|
|
43
|
+
@output_folder = File.expand_path(File.join(@project_folder, output_folder))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns the effective output folder. If a workspace exists, this will
|
|
47
|
+
# return the workspace's output folder. If not, it will return the
|
|
48
|
+
# project's output folder.
|
|
49
|
+
def effective_output_folder
|
|
50
|
+
if Workspace.have_workspace?
|
|
51
|
+
relative_project_location = Utils::path_difference(Workspace.workspace.workspace_folder, @project_folder)
|
|
52
|
+
fail "Project folder '#{@project_folder}' must be within workspace folder '#{Workspace.workspace.workspace_folder}'." if relative_project_location.nil?
|
|
53
|
+
return File.join(Workspace.workspace.output_folder, relative_project_location)
|
|
54
|
+
else
|
|
55
|
+
return @output_folder
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def add_configuration(configuration_name, configuration)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def create_configuration_tasks(configuration_name, configuration)
|
|
65
|
+
check_configuration(configuration_name, configuration)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
include Rake::DSL
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module MTBuild
|
|
2
|
+
require 'mtbuild/compiled_configuration'
|
|
3
|
+
|
|
4
|
+
# Use this class to create static library configurations. You won't typically
|
|
5
|
+
# instantiate this directly. Instead, the StaticLibraryProject.add_configuration
|
|
6
|
+
# method will create this for you.
|
|
7
|
+
class StaticLibraryConfiguration < CompiledConfiguration
|
|
8
|
+
|
|
9
|
+
# API header location for the static library
|
|
10
|
+
attr_reader :api_headers
|
|
11
|
+
|
|
12
|
+
def initialize(project_name, project_folder, output_folder, configuration_name, configuration)
|
|
13
|
+
super
|
|
14
|
+
@api_headers = Utils.expand_folder_list(configuration.fetch(:api_headers, []), @project_folder)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Create the actual Rake tasks that will perform the configuration's work
|
|
18
|
+
def configure_tasks
|
|
19
|
+
super
|
|
20
|
+
all_object_files = []
|
|
21
|
+
all_object_folders = []
|
|
22
|
+
@toolchains.each do |toolchain, sources|
|
|
23
|
+
toolchain.add_include_paths(@api_headers)
|
|
24
|
+
object_files, object_folders = toolchain.create_compile_tasks(sources)
|
|
25
|
+
all_object_files |= object_files
|
|
26
|
+
all_object_folders |= object_folders
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
library_files, library_folders = @default_toolchain.create_static_library_tasks(all_object_files, @project_name)
|
|
30
|
+
dependencies = @dependencies+all_object_folders+library_folders+library_files
|
|
31
|
+
|
|
32
|
+
desc "Build library '#{@project_name}' with configuration '#{@configuration_name}'"
|
|
33
|
+
new_task = static_library_task @configuration_name => dependencies do |t|
|
|
34
|
+
puts "built library #{t.name}."
|
|
35
|
+
@tests.each do |test|
|
|
36
|
+
if Rake::Task.task_defined? test
|
|
37
|
+
Rake::Task[test].invoke
|
|
38
|
+
else
|
|
39
|
+
$stderr.puts "warning: Skipping unknown test '#{test}'"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
new_task.api_headers = @api_headers
|
|
44
|
+
new_task.library_files = library_files
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|