akro 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/bin/akro +42 -0
- data/lib/akro.rb +135 -0
- data/lib/akrobuild.rake +492 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c69ca34e3c6f0e691cf032931d3f1fa8a7fa7b95
|
4
|
+
data.tar.gz: 015d35f735e0bbde0d93774f0c989d82df53429e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3257b2d6318db6f815cad2663df2f914b5a1fcb6ecf23bbb985fb9c4abac63ee43267c84ab4cdba678dce52c8122561c0b8b5393c8a7e5f8c122e7a09157f2c0
|
7
|
+
data.tar.gz: 18e0a729c4906341b6655d3fa0c112946ba9a885ba2fb63da99a5a057752649eb8b7db1cac2776443ff458c24fc7c3eaf01649e5016701e7e00e80b0e7361b52
|
data/bin/akro
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright (c) 2016 Vlad Petric
|
4
|
+
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to
|
7
|
+
# deal in the Software without restriction, including without limitation the
|
8
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
9
|
+
# sell copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
20
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
21
|
+
# IN THE SOFTWARE.
|
22
|
+
|
23
|
+
|
24
|
+
# At the top level, Akro is a wrapper around rake. The reason for
|
25
|
+
# the wrapping is that rake does not allow pre-loads before the
|
26
|
+
# rakefile.
|
27
|
+
# Akro needs to define several functions: add_test, add_binary(ies),
|
28
|
+
# add_library before a rakefile is processed. The akro main file,
|
29
|
+
# akrobuild.rake, is postloaded.
|
30
|
+
#
|
31
|
+
begin
|
32
|
+
require 'rubygems'
|
33
|
+
gem 'akro'
|
34
|
+
rescue LoadError
|
35
|
+
end
|
36
|
+
#preload
|
37
|
+
require 'akro'
|
38
|
+
|
39
|
+
#postload - will only be handled after the rakefile
|
40
|
+
rake_import = "#{File.dirname(File.dirname(File.realdirpath(__FILE__)))}/lib/akrobuild.rake"
|
41
|
+
Rake.application.add_import(rake_import)
|
42
|
+
Rake.application.run
|
data/lib/akro.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
# Copyright (c) 2016 Vlad Petric
|
2
|
+
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to
|
5
|
+
# deal in the Software without restriction, including without limitation the
|
6
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
# sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
18
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
19
|
+
# IN THE SOFTWARE.
|
20
|
+
|
21
|
+
require 'rake'
|
22
|
+
|
23
|
+
$VERBOSE_BUILD = false
|
24
|
+
|
25
|
+
# Use $COMPILER_PREFIX for things like ccache
|
26
|
+
$COMPILER_PREFIX = nil
|
27
|
+
$COMPILER = "g++"
|
28
|
+
$COMPILE_FLAGS = "-Wall"
|
29
|
+
$MODE_COMPILE_FLAGS = {
|
30
|
+
"debug" => "-g3",
|
31
|
+
"release" => "-O3 -g3"
|
32
|
+
}
|
33
|
+
|
34
|
+
$AR = "ar"
|
35
|
+
|
36
|
+
# nil for linker means - use the same as the compiler
|
37
|
+
$LINKER = nil
|
38
|
+
$LINKER_PREFIX = nil
|
39
|
+
$LINK_FLAGS = nil
|
40
|
+
$MODE_LINK_FLAGS = nil
|
41
|
+
# $ADDITIONAL_LINK_FLAGS is for third party libraries and objects
|
42
|
+
$ADDITIONAL_LINK_FLAGS = ""
|
43
|
+
|
44
|
+
$HEADER_EXTENSIONS = [".h", ".hpp", ".H"]
|
45
|
+
$CPP_EXTENSIONS = [".c", ".cc", ".cpp", ".cxx", ".c++", ".C"]
|
46
|
+
$OBJ_EXTENSION = ".o"
|
47
|
+
$STATIC_LIB_EXTENSION = ".a"
|
48
|
+
$DYNAMIC_LIB_EXTENSION = ".so"
|
49
|
+
|
50
|
+
$LIB_CAPTURE_MAP = Hash.new
|
51
|
+
|
52
|
+
AkroTest = Struct.new("AkroTest", :name, :script, :binary, :cmdline)
|
53
|
+
$AKRO_TESTS = []
|
54
|
+
$AKRO_TESTS_MAP = Hash.new
|
55
|
+
def add_test(name: nil, script: nil, binary: nil, cmdline: nil)
|
56
|
+
raise "Test must have a name" if name.nil?
|
57
|
+
raise "Test must have at least a script and a binary" if script.nil? and binary.nil?
|
58
|
+
raise "Binary must end in .exe" if !binary.nil? and !binary.end_with?(".exe")
|
59
|
+
test = AkroTest.new(name, script, binary, cmdline)
|
60
|
+
$AKRO_TESTS << test
|
61
|
+
raise "Test #{name} appears multiple times" if $AKRO_TESTS_MAP.has_key?(name)
|
62
|
+
$AKRO_TESTS_MAP[name] = test
|
63
|
+
end
|
64
|
+
|
65
|
+
$AKRO_BINARIES = []
|
66
|
+
def add_binary(path)
|
67
|
+
$AKRO_BINARIES << path.to_str()
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_binaries(*paths)
|
71
|
+
paths.each do |path|
|
72
|
+
$AKRO_BINARIES << path.to_str()
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
AkroLibrary = Struct.new("AkroLibrary", :path, :sources, :static, :recurse, :capture_deps, :additional_params)
|
77
|
+
$AKRO_LIBS = []
|
78
|
+
|
79
|
+
def add_static_library(path: nil, sources: nil, recurse: true, capture_deps: true, additional_params: nil)
|
80
|
+
raise "Must specify path for static library" if path.nil?
|
81
|
+
raise "Must specify source for static library #{path}" if sources.nil?
|
82
|
+
$AKRO_LIBS << AkroLibrary.new(path, sources, true, recurse, capture_deps, additional_params)
|
83
|
+
end
|
84
|
+
def add_dynamic_library(path: nil, sources: nil, recurse: true, capture_deps: true, additional_params: nil)
|
85
|
+
raise "Must specify path for dynamic library" if path.nil?
|
86
|
+
raise "Must specify source for dynamic library #{path}" if sources.nil?
|
87
|
+
$AKRO_LIBS << AkroLibrary.new(path, sources, false, recurse, capture_deps, additional_params)
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_tests(*tests)
|
91
|
+
tests.each do |t|
|
92
|
+
if t.respond_to?(:to_str)
|
93
|
+
s = t.to_str()
|
94
|
+
add_test(name: s, script: s, binary: s, cmdline: nil)
|
95
|
+
elsif t.is_a?(AkroTest)
|
96
|
+
$AKRO_TESTS << t
|
97
|
+
else
|
98
|
+
raise "Can't add test of class #{t.class.name} "
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Module with overrideable command line functions
|
104
|
+
module CmdLine
|
105
|
+
def CmdLine.compile_base_cmdline(mode)
|
106
|
+
"#{$COMPILER_PREFIX}#{$COMPILER} #{$COMPILE_FLAGS} #{$MODE_COMPILE_FLAGS[mode]}"
|
107
|
+
end
|
108
|
+
def CmdLine.dependency_cmdline(mode, src)
|
109
|
+
"#{CmdLine.compile_base_cmdline(mode)} -M #{src}"
|
110
|
+
end
|
111
|
+
def CmdLine.compile_cmdline(mode, src, obj)
|
112
|
+
"#{CmdLine.compile_base_cmdline(mode)} -c #{src} -o #{obj}"
|
113
|
+
end
|
114
|
+
def CmdLine.link_cmdline(mode, objs, bin)
|
115
|
+
"#{$LINKER_PREFIX}#{$LINKER} #{$LINK_FLAGS} #{$MODE_LINK_FLAGS[mode]} #{objs.join(' ')} #{$ADDITIONAL_LINK_FLAGS} -o #{bin}"
|
116
|
+
end
|
117
|
+
def CmdLine.static_lib_cmdline(objs, bin)
|
118
|
+
"#{$AR} rcs #{bin} #{objs.join(' ')}"
|
119
|
+
end
|
120
|
+
def CmdLine.dynamic_lib_cmdline(mode, objs, additional_params, bin)
|
121
|
+
if !additional_params.nil?
|
122
|
+
if additional_params.kind_of?(Array)
|
123
|
+
extra_params = " " + objs.join(" ")
|
124
|
+
elsif additional_params.respond_to?(:to_str)
|
125
|
+
extra_params = " " + additional_params.to_str
|
126
|
+
else
|
127
|
+
raise "Additional params to a dynamic library must be either a string or an array of strings"
|
128
|
+
end
|
129
|
+
else
|
130
|
+
extra_params = ""
|
131
|
+
end
|
132
|
+
soname = if bin.include?("/") then FileMapper.strip_mode(bin) else bin end
|
133
|
+
"#{$LINKER_PREFIX}#{$COMPILER} -shared #{$COMPILE_FLAGS} #{$MODE_COMPILE_FLAGS[mode]} -Wl,-soname,#{soname} -o #{bin} #{objs.join(' ')}#{extra_params}"
|
134
|
+
end
|
135
|
+
end
|
data/lib/akrobuild.rake
ADDED
@@ -0,0 +1,492 @@
|
|
1
|
+
# Copyright (c) 2016 Vlad Petric
|
2
|
+
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to
|
5
|
+
# deal in the Software without restriction, including without limitation the
|
6
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
# sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
18
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
19
|
+
# IN THE SOFTWARE.
|
20
|
+
|
21
|
+
$MODES = $MODE_COMPILE_FLAGS.keys
|
22
|
+
$COMPILER_PREFIX = $COMPILER_PREFIX.nil? ? "" : $COMPILER_PREFIX + " "
|
23
|
+
$LINKER_PREFIX = $LINKER_PREFIX.nil? ? $COMPILER_PREFIX : $LINKER_PREFIX + " "
|
24
|
+
$LINKER = $LINKER.nil? ? $COMPILER : $LINKER
|
25
|
+
$LINK_FLAGS = $LINK_FLAGS.nil? ? $COMPILE_FLAGS : $LINK_FLAGS
|
26
|
+
$MODE_LINK_FLAGS = $MODE_LINK_FLAGS.nil? ? $MODE_COMPILE_FLAGS : $MODE_LINK_FLAGS
|
27
|
+
|
28
|
+
module Util
|
29
|
+
def Util.make_relative_path(path)
|
30
|
+
absolute_path = File.absolute_path(path)
|
31
|
+
base_dir = File.absolute_path(Dir.pwd)
|
32
|
+
base_dir << '/' if !base_dir.end_with?('/')
|
33
|
+
r = absolute_path.start_with?(base_dir) ? absolute_path[base_dir.size..-1] : nil
|
34
|
+
if !r.nil? && r.start_with?('/')
|
35
|
+
raise "Relative path #{r} is not relative"
|
36
|
+
end
|
37
|
+
r
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module FileMapper
|
42
|
+
# Extract build mode from path.
|
43
|
+
# E.g., debug/a/b/c.o returns debug.
|
44
|
+
def FileMapper.get_mode(path)
|
45
|
+
rel_path = Util.make_relative_path(path)
|
46
|
+
raise "Path #{path} does not belong to #{Dir.pwd}" if rel_path.nil?
|
47
|
+
mode = rel_path[/^([^\/]*)/, 1]
|
48
|
+
raise "Unknown mode #{mode} for #{path}" if !$MODES.include?(mode)
|
49
|
+
mode
|
50
|
+
end
|
51
|
+
def FileMapper.get_mode_from_dc(path)
|
52
|
+
rel_path = Util.make_relative_path(path)
|
53
|
+
raise "Path #{path} does not belong to #{Dir.pwd}" if rel_path.nil?
|
54
|
+
mode = rel_path[/^\.akro\/([^\/]*)/, 1]
|
55
|
+
raise "Unknown mode #{mode} for #{path}" if !$MODES.include?(mode)
|
56
|
+
mode
|
57
|
+
end
|
58
|
+
# Strip the build mode from path.
|
59
|
+
def FileMapper.strip_mode(path)
|
60
|
+
rel_path = Util.make_relative_path(path)
|
61
|
+
raise "Path #{path} does not belong to #{Dir.pwd}" if rel_path.nil?
|
62
|
+
get_mode(rel_path) # for sanity checking
|
63
|
+
rel_path[/^[^\/]*\/(.*)$/, 1]
|
64
|
+
end
|
65
|
+
# Maps object file to its corresponding depcache file.
|
66
|
+
# E.g., release/a/b/c.o maps to .akro/release/a/b/c.depcache
|
67
|
+
def FileMapper.map_obj_to_dc(path)
|
68
|
+
FileMapper.get_mode(path)
|
69
|
+
raise "#{path} is not a #{$OBJ_EXTENSION} file" if !path.end_with?($OBJ_EXTENSION)
|
70
|
+
".akro/#{path[0..-$OBJ_EXTENSION.length-1]}.depcache"
|
71
|
+
end
|
72
|
+
# Maps object file to its corresponding cpp file, if it exists.
|
73
|
+
# E.g., release/a/b/c.o maps to a/b/c{.cpp,.cc,.cxx,.c++}
|
74
|
+
def FileMapper.map_obj_to_cpp(path)
|
75
|
+
raise "#{path} is not a #{$OBJ_EXTENSION} file" if !path.end_with?($OBJ_EXTENSION)
|
76
|
+
file = FileMapper.strip_mode(path)
|
77
|
+
file = file[0..-$OBJ_EXTENSION.length-1]
|
78
|
+
srcs = $CPP_EXTENSIONS.map{|ext| file + ext}.select{|fname| File.exist?(fname)}
|
79
|
+
raise "Multiple sources for base name #{file}: #{srcs.join(' ')}" if srcs.length > 1
|
80
|
+
srcs.length == 0? nil : srcs[0]
|
81
|
+
end
|
82
|
+
def FileMapper.map_cpp_to_dc(mode, path)
|
83
|
+
$CPP_EXTENSIONS.map do |ext|
|
84
|
+
return ".akro/#{mode}/#{path[0..-ext.length-1]}.depcache" if path.end_with?(ext)
|
85
|
+
end
|
86
|
+
raise "#{path} is not one of: #{$CPP_EXTENSIONS.join(',')}"
|
87
|
+
end
|
88
|
+
def FileMapper.map_cpp_to_obj(mode, path)
|
89
|
+
$CPP_EXTENSIONS.map do |ext|
|
90
|
+
return "#{mode}/#{path[0..-ext.length-1]}#{$OBJ_EXTENSION}" if path.end_with?(ext)
|
91
|
+
end
|
92
|
+
raise "#{path} is not one of: #{$CPP_EXTENSIONS.join(',')}"
|
93
|
+
end
|
94
|
+
# Maps depcache file to its corresponding cpp file, which should exist.
|
95
|
+
# E.g., .akro/release/a/b/c.o maps to a/b/c{.cpp,.cc,.cxx,.c++}
|
96
|
+
def FileMapper.map_dc_to_cpp(path)
|
97
|
+
raise "#{path} is not a .depcache file" if !path.end_with?('.depcache') || !path.start_with?('.akro')
|
98
|
+
file = path[/^\.akro\/(.*)\.depcache$/, 1]
|
99
|
+
file = FileMapper.strip_mode(file)
|
100
|
+
srcs = $CPP_EXTENSIONS.map{|ext| file + ext}.select{|fname| File.exist?(fname)}
|
101
|
+
raise "Multiple sources for base name #{file}: #{srcs.join(' ')}" if srcs.length > 1
|
102
|
+
raise "No sources for base name #{file}" if srcs.length == 0
|
103
|
+
srcs[0]
|
104
|
+
end
|
105
|
+
def FileMapper.map_dc_to_compcmd(path)
|
106
|
+
raise "#{path} is not a .depcache file" if !path.end_with?('.depcache') || !path.start_with?('.akro')
|
107
|
+
path.gsub(/\.depcache$/, ".compcmd" )
|
108
|
+
end
|
109
|
+
def FileMapper.map_exe_to_linkcmd(path)
|
110
|
+
".akro/#{path.gsub(/\.exe$/, ".linkcmd" )}"
|
111
|
+
end
|
112
|
+
def FileMapper.map_linkcmd_to_exe(path)
|
113
|
+
path[/^.akro\/(.*)\.linkcmd$/, 1] + ".exe"
|
114
|
+
end
|
115
|
+
def FileMapper.map_static_lib_to_linkcmd(path)
|
116
|
+
".akro/#{path.gsub(/#{$STATIC_LIB_EXTENSION}$/, ".stlinkcmd" )}"
|
117
|
+
end
|
118
|
+
def FileMapper.map_linkcmd_to_static_lib(path)
|
119
|
+
path[/^.akro\/(.*)\.stlinkcmd$/, 1] + $STATIC_LIB_EXTENSION
|
120
|
+
end
|
121
|
+
def FileMapper.map_dynamic_lib_to_linkcmd(path)
|
122
|
+
".akro/#{path.gsub(/#{$DYNAMIC_LIB_EXTENSION}$/, ".dynlinkcmd" )}"
|
123
|
+
end
|
124
|
+
def FileMapper.map_linkcmd_to_dynamic_lib(path)
|
125
|
+
path[/^.akro\/(.*)\.dynlinkcmd$/, 1] + $DYNAMIC_LIB_EXTENSION
|
126
|
+
end
|
127
|
+
# Maps header file to its corresponding cpp file, if it exists
|
128
|
+
# E.g., a/b/c.h maps to a/b/c.cpp, if a/b/c.cpp exists, otherwise nil
|
129
|
+
def FileMapper.map_header_to_cpp(path)
|
130
|
+
rel_path = Util.make_relative_path(path)
|
131
|
+
# file is not local
|
132
|
+
return nil if rel_path.nil?
|
133
|
+
#$HEADER_EXTENSIONS.select{|ext| rel_path.end_with?(ext)}.each do |ext|
|
134
|
+
#end
|
135
|
+
srcs = $HEADER_EXTENSIONS.select{|ext| rel_path.end_with?(ext)}.collect{ |ext|
|
136
|
+
base_path = rel_path[0..-ext.length-1]
|
137
|
+
$CPP_EXTENSIONS.map{|cppext| base_path + cppext}.select{|file| File.exist?(file)}
|
138
|
+
}.flatten.uniq
|
139
|
+
raise "Multiple sources for base name #{path}: #{srcs.join(' ')}" if srcs.length > 1
|
140
|
+
srcs.length == 0? nil : srcs[0]
|
141
|
+
end
|
142
|
+
|
143
|
+
def FileMapper.map_script_to_exe(path)
|
144
|
+
path_no_ext = path[/^(.*)[^.\/]*$/, 1]
|
145
|
+
srcs = $CPP_EXTENSIONS.map{|cppext| path + cppext}.select{|file| File.exist?(file)}
|
146
|
+
srcs.length == 0? nil : path + ".exe"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
#Builder encapsulates the compilation/linking/dependecy checking functionality
|
151
|
+
module Builder
|
152
|
+
def Builder.create_depcache(src, dc)
|
153
|
+
success = false
|
154
|
+
mode = FileMapper.get_mode_from_dc(dc)
|
155
|
+
basedir, _ = File.split(dc)
|
156
|
+
FileUtils.mkdir_p(basedir)
|
157
|
+
output = File.open(dc, "w")
|
158
|
+
puts "Determining dependencies for #{dc}" if $VERBOSE_BUILD
|
159
|
+
begin
|
160
|
+
#Using backticks as Rake's sh outputs the command. Don't want that here.
|
161
|
+
cmdline = CmdLine.dependency_cmdline(mode, src)
|
162
|
+
puts cmdline if $VERBOSE_BUILD
|
163
|
+
deps = `#{cmdline}`
|
164
|
+
raise "Dependency determination failed for #{src}" if $?.to_i != 0
|
165
|
+
# NOTE(vlad): spaces within included filenames are not supported
|
166
|
+
# Get rid of \ at the end of lines, and also of the newline
|
167
|
+
deps.gsub!(/\\\n/, '')
|
168
|
+
# also get rid of <filename>: at the beginning
|
169
|
+
deps[/^[^:]*:(.*)$/, 1].split(' ').each do |line|
|
170
|
+
# Output either a relative path if the file is local, or the original line.
|
171
|
+
output << (Util.make_relative_path(line.strip) || line) << "\n"
|
172
|
+
end
|
173
|
+
output.close
|
174
|
+
success = true
|
175
|
+
ensure
|
176
|
+
FileUtils.rm(dc) if !success
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def Builder.compile_object(src, obj)
|
181
|
+
mode = FileMapper.get_mode(obj)
|
182
|
+
basedir, _ = File.split(obj)
|
183
|
+
FileUtils.mkdir_p(basedir)
|
184
|
+
RakeFileUtils::sh(CmdLine.compile_cmdline(mode, src, obj)) do |ok, res|
|
185
|
+
raise "Compilation failed for #{src}" if !ok
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def Builder.link_binary(objs, bin)
|
190
|
+
mode = FileMapper.get_mode(bin)
|
191
|
+
basedir, _ = File.split(bin)
|
192
|
+
FileUtils.mkdir_p(basedir)
|
193
|
+
RakeFileUtils::sh(CmdLine.link_cmdline(mode, objs, bin)) do |ok, res|
|
194
|
+
raise "Linking failed for #{bin}" if !ok
|
195
|
+
end
|
196
|
+
end
|
197
|
+
def Builder.archive_static_library(objs, bin)
|
198
|
+
basedir, _ = File.split(bin)
|
199
|
+
FileUtils.mkdir_p(basedir)
|
200
|
+
RakeFileUtils::sh(CmdLine.static_lib_cmdline(objs, bin)) do |ok, res|
|
201
|
+
raise "Archiving failed for #{bin}" if !ok
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def Builder.build_dynamic_library(mode, objs, additional_params, bin)
|
206
|
+
mode = FileMapper.get_mode(bin)
|
207
|
+
basedir, _ = File.split(bin)
|
208
|
+
FileUtils.mkdir_p(basedir)
|
209
|
+
RakeFileUtils::sh(CmdLine.dynamic_lib_cmdline(mode, objs, additional_params, bin)) do |ok, res|
|
210
|
+
raise "Building dynamic library #{bin} failed" if !ok
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def Builder.depcache_object_collect(mode, top_level_srcs)
|
215
|
+
all_covered_cpps = Set.new
|
216
|
+
all_objects = []
|
217
|
+
srcs = top_level_srcs
|
218
|
+
while !srcs.empty?
|
219
|
+
new_srcs = []
|
220
|
+
dcs = srcs.map{|src| FileMapper.map_cpp_to_dc(mode, src)}
|
221
|
+
dcs.each{|dc| Rake::Task[dc].invoke}
|
222
|
+
dcs.each do |dc|
|
223
|
+
cpp = FileMapper.map_dc_to_cpp(dc)
|
224
|
+
obj = FileMapper.map_cpp_to_obj(mode, cpp)
|
225
|
+
all_objects << obj if !all_objects.include?(obj)
|
226
|
+
File.readlines(dc).map{|line| line.strip}.each do |header|
|
227
|
+
new_cpp = FileMapper.map_header_to_cpp(header)
|
228
|
+
if !new_cpp.nil? and !all_covered_cpps.include?(new_cpp)
|
229
|
+
new_srcs << new_cpp
|
230
|
+
all_covered_cpps << new_cpp
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
srcs = new_srcs
|
235
|
+
end
|
236
|
+
all_objects
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
#Phony task that forces anything depending on it to run
|
241
|
+
task "always"
|
242
|
+
|
243
|
+
rule ".compcmd" => ->(dc) {
|
244
|
+
mode = FileMapper.get_mode_from_dc(dc)
|
245
|
+
cmd = CmdLine.compile_base_cmdline(mode)
|
246
|
+
if File.exists?(dc) && File.read(dc).strip == cmd.strip then
|
247
|
+
[]
|
248
|
+
else
|
249
|
+
"always"
|
250
|
+
end
|
251
|
+
} do |task|
|
252
|
+
basedir, _ = File.split(task.name)
|
253
|
+
FileUtils.mkdir_p(basedir)
|
254
|
+
output = File.open(task.name, "w")
|
255
|
+
mode = FileMapper.get_mode_from_dc(task.name)
|
256
|
+
output << CmdLine.compile_base_cmdline(mode) << "\n"
|
257
|
+
output.close
|
258
|
+
end
|
259
|
+
|
260
|
+
rule ".linkcmd" => ->(dc) {
|
261
|
+
binary = FileMapper.map_linkcmd_to_exe(dc)
|
262
|
+
raise "Internal error - linkcmd not mapped for #{binary}" if !$LINK_BINARY_OBJS.has_key?(binary)
|
263
|
+
mode = FileMapper.get_mode_from_dc(dc)
|
264
|
+
cmd = CmdLine.link_cmdline(mode, $LINK_BINARY_OBJS[binary], "<placeholder>")
|
265
|
+
if File.exists?(dc) && File.read(dc).strip == cmd.strip then
|
266
|
+
[]
|
267
|
+
else
|
268
|
+
"always"
|
269
|
+
end
|
270
|
+
} do |task|
|
271
|
+
basedir, _ = File.split(task.name)
|
272
|
+
binary = FileMapper.map_linkcmd_to_exe(task.name)
|
273
|
+
FileUtils.mkdir_p(basedir)
|
274
|
+
output = File.open(task.name, "w")
|
275
|
+
mode = FileMapper.get_mode_from_dc(task.name)
|
276
|
+
output << CmdLine.link_cmdline(mode, $LINK_BINARY_OBJS[binary], "<placeholder>") << "\n"
|
277
|
+
output.close
|
278
|
+
end
|
279
|
+
|
280
|
+
rule ".dynlinkcmd" => ->(dc) {
|
281
|
+
dynlib = FileMapper.map_linkcmd_to_dynamic_lib(dc)
|
282
|
+
raise "Internal error - linkcmd not mapped for #{dynlib}" if !$LINK_BINARY_OBJS.has_key?(dynlib)
|
283
|
+
mode = FileMapper.get_mode_from_dc(dc)
|
284
|
+
cmd = CmdLine.dynamic_lib_cmdline(mode, $LINK_BINARY_OBJS[dynlib], "", "<placeholder>")
|
285
|
+
if File.exists?(dc) && File.read(dc).strip == cmd.strip then
|
286
|
+
[]
|
287
|
+
else
|
288
|
+
"always"
|
289
|
+
end
|
290
|
+
} do |task|
|
291
|
+
basedir, _ = File.split(task.name)
|
292
|
+
dynlib = FileMapper.map_linkcmd_to_dynamic_lib(task.name)
|
293
|
+
FileUtils.mkdir_p(basedir)
|
294
|
+
output = File.open(task.name, "w")
|
295
|
+
mode = FileMapper.get_mode_from_dc(task.name)
|
296
|
+
output << CmdLine.dynamic_lib_cmdline(mode, $LINK_BINARY_OBJS[dynlib], "", "<placeholder>") << "\n"
|
297
|
+
output.close
|
298
|
+
end
|
299
|
+
|
300
|
+
rule ".stlinkcmd" => ->(dc) {
|
301
|
+
stlib = FileMapper.map_linkcmd_to_static_lib(dc)
|
302
|
+
raise "Internal error - linkcmd not mapped for #{stlib}" if !$LINK_BINARY_OBJS.has_key?(stlib)
|
303
|
+
mode = FileMapper.get_mode_from_dc(dc)
|
304
|
+
cmd = CmdLine.static_lib_cmdline($LINK_BINARY_OBJS[stlib], "<placeholder>")
|
305
|
+
if File.exists?(dc) && File.read(dc).strip == cmd.strip then
|
306
|
+
[]
|
307
|
+
else
|
308
|
+
"always"
|
309
|
+
end
|
310
|
+
} do |task|
|
311
|
+
basedir, _ = File.split(task.name)
|
312
|
+
stlib = FileMapper.map_linkcmd_to_static_lib(task.name)
|
313
|
+
FileUtils.mkdir_p(basedir)
|
314
|
+
output = File.open(task.name, "w")
|
315
|
+
mode = FileMapper.get_mode_from_dc(task.name)
|
316
|
+
output << CmdLine.static_lib_cmdline($LINK_BINARY_OBJS[stlib], "<placeholder>") << "\n"
|
317
|
+
output.close
|
318
|
+
end
|
319
|
+
|
320
|
+
|
321
|
+
rule ".depcache" => ->(dc){
|
322
|
+
[FileMapper.map_dc_to_compcmd(dc), FileMapper.map_dc_to_cpp(dc)] +
|
323
|
+
(File.exist?(dc) ? File.readlines(dc).map{|line| line.strip}: [])
|
324
|
+
} do |task|
|
325
|
+
src = FileMapper.map_dc_to_cpp(task.name)
|
326
|
+
Builder.create_depcache(src, task.name)
|
327
|
+
end
|
328
|
+
|
329
|
+
rule $OBJ_EXTENSION => ->(obj){
|
330
|
+
src = FileMapper.map_obj_to_cpp(obj)
|
331
|
+
raise "No source for object file #{obj}" if src.nil?
|
332
|
+
dc = FileMapper.map_obj_to_dc(obj)
|
333
|
+
[src, dc, FileMapper.map_dc_to_compcmd(dc)] +
|
334
|
+
(File.exist?(dc) ? File.readlines(dc).map{|line| line.strip}: [])
|
335
|
+
} do |task|
|
336
|
+
src = FileMapper.map_obj_to_cpp(task.name)
|
337
|
+
Builder.compile_object(src, task.name)
|
338
|
+
end
|
339
|
+
|
340
|
+
def libname(mode, lib)
|
341
|
+
"#{mode}/#{lib.path}#{if lib.static then $STATIC_LIB_EXTENSION else $DYNAMIC_LIB_EXTENSION end}"
|
342
|
+
end
|
343
|
+
|
344
|
+
def invoke_all_capturing_libs(mode)
|
345
|
+
$AKRO_LIBS.each do |lib|
|
346
|
+
if lib.capture_deps
|
347
|
+
Rake::Task[libname(mode, lib)].invoke
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
$LINK_BINARY_OBJS = Hash.new
|
353
|
+
|
354
|
+
rule ".exe" => ->(binary){
|
355
|
+
obj = binary.gsub(/\.exe$/, $OBJ_EXTENSION)
|
356
|
+
mode = FileMapper.get_mode(binary)
|
357
|
+
cpp = FileMapper.map_obj_to_cpp(obj)
|
358
|
+
raise "No proper #{$CPP_EXTENSIONS.join(',')} file found for #{binary}" if cpp.nil?
|
359
|
+
obj_list = []
|
360
|
+
# Two passes through the object list - the capturing libraries will
|
361
|
+
# be inserted on the position of the *last* object in the list
|
362
|
+
last_obj = Hash.new
|
363
|
+
objs = Builder.depcache_object_collect(mode, [cpp])
|
364
|
+
objs.each do |obj|
|
365
|
+
if $LIB_CAPTURE_MAP.has_key?(obj)
|
366
|
+
last_obj[$LIB_CAPTURE_MAP[obj]] = obj
|
367
|
+
end
|
368
|
+
end
|
369
|
+
objs.each do |obj|
|
370
|
+
if $LIB_CAPTURE_MAP.has_key?(obj)
|
371
|
+
capture_lib = $LIB_CAPTURE_MAP[obj]
|
372
|
+
if last_obj[capture_lib] == obj
|
373
|
+
obj_list << capture_lib
|
374
|
+
end
|
375
|
+
else
|
376
|
+
obj_list << obj
|
377
|
+
end
|
378
|
+
end
|
379
|
+
$LINK_BINARY_OBJS[binary] = obj_list
|
380
|
+
[FileMapper.map_exe_to_linkcmd(binary)] + obj_list
|
381
|
+
} do |task|
|
382
|
+
Builder.link_binary(task.prerequisites[1..-1], task.name)
|
383
|
+
end
|
384
|
+
|
385
|
+
rule $STATIC_LIB_EXTENSION => ->(library) {
|
386
|
+
mode = FileMapper.get_mode(library)
|
387
|
+
srcs = []
|
388
|
+
lib = FileMapper.strip_mode(library)[0..-$STATIC_LIB_EXTENSION.length-1]
|
389
|
+
libspec = nil
|
390
|
+
$AKRO_LIBS.each do |alib|
|
391
|
+
if alib.path == lib and alib.static
|
392
|
+
raise "Library #{library} declared multiple times" if !libspec.nil?
|
393
|
+
libspec = alib
|
394
|
+
srcs << alib.sources
|
395
|
+
end
|
396
|
+
end
|
397
|
+
raise "Library #{library} not found!" if libspec.nil?
|
398
|
+
srcs.flatten!
|
399
|
+
if libspec.recurse
|
400
|
+
objs = Builder.depcache_object_collect(mode, srcs)
|
401
|
+
else
|
402
|
+
objs = srcs.collect{|src| FileMapper.map_cpp_to_obj(mode, src)}
|
403
|
+
end
|
404
|
+
if libspec.capture_deps
|
405
|
+
objs.each do |obj|
|
406
|
+
if $LIB_CAPTURE_MAP.has_key?(obj)
|
407
|
+
raise "Object #{obj} has dependency captures for multiple libraries - #{$LIB_CAPTURE_MAP[obj]} and #{library}"
|
408
|
+
end
|
409
|
+
$LIB_CAPTURE_MAP[obj] = library
|
410
|
+
end
|
411
|
+
end
|
412
|
+
$LINK_BINARY_OBJS[library] = objs
|
413
|
+
[FileMapper.map_static_lib_to_linkcmd(library)] + objs
|
414
|
+
} do |task|
|
415
|
+
Builder.archive_static_library(task.prerequisites[1..-1], task.name)
|
416
|
+
end
|
417
|
+
|
418
|
+
rule $DYNAMIC_LIB_EXTENSION => ->(library) {
|
419
|
+
mode = FileMapper.get_mode(library)
|
420
|
+
srcs = []
|
421
|
+
lib = FileMapper.strip_mode(library)[0..-$DYNAMIC_LIB_EXTENSION.length-1]
|
422
|
+
libspec = nil
|
423
|
+
$AKRO_LIBS.each do |alib|
|
424
|
+
if alib.path == lib and not alib.static
|
425
|
+
raise "Library #{library} declared multiple times" if !libspec.nil?
|
426
|
+
libspec = alib
|
427
|
+
srcs << alib.sources
|
428
|
+
end
|
429
|
+
end
|
430
|
+
raise "Library #{library} not found!" if libspec.nil?
|
431
|
+
srcs.flatten!
|
432
|
+
if libspec.recurse
|
433
|
+
objs = Builder.depcache_object_collect(mode, srcs)
|
434
|
+
else
|
435
|
+
objs = srcs.collect{|src| FileMapper.map_cpp_to_obj(mode, src)}
|
436
|
+
end
|
437
|
+
if libspec.capture_deps
|
438
|
+
objs.each do |obj|
|
439
|
+
if $LIB_CAPTURE_MAP.has_key?(obj)
|
440
|
+
raise "Object #{obj} has dependency captures for multiple libraries - #{$LIB_CAPTURE_MAP[obj]} and #{library}"
|
441
|
+
end
|
442
|
+
$LIB_CAPTURE_MAP[obj] = library
|
443
|
+
end
|
444
|
+
end
|
445
|
+
$LINK_BINARY_OBJS[library] = objs
|
446
|
+
[FileMapper.map_dynamic_lib_to_linkcmd(library)] + objs
|
447
|
+
} do |task|
|
448
|
+
libspec = nil
|
449
|
+
lib = FileMapper.strip_mode(task.name)[0..-$DYNAMIC_LIB_EXTENSION.length-1]
|
450
|
+
$AKRO_LIBS.each do |alib|
|
451
|
+
if alib.path == lib and not alib.static
|
452
|
+
libspec = alib
|
453
|
+
end
|
454
|
+
end
|
455
|
+
mode = FileMapper.get_mode(task.name)
|
456
|
+
Builder.build_dynamic_library(mode, task.prerequisites[1..-1], libspec.additional_params, task.name)
|
457
|
+
end
|
458
|
+
|
459
|
+
task :clean do
|
460
|
+
FileUtils::rm_rf(".akro/")
|
461
|
+
$MODES.each{|mode| FileUtils::rm_rf("#{mode}/")}
|
462
|
+
end
|
463
|
+
|
464
|
+
$MODES.each do |mode|
|
465
|
+
invoke_all_capturing_libs(mode)
|
466
|
+
task mode
|
467
|
+
task "test_#{mode}"
|
468
|
+
$AKRO_BINARIES.each do |bin|
|
469
|
+
raise "Binary cannot start with mode #{bin}" if bin.start_with?(mode + "/")
|
470
|
+
Rake::Task[mode].enhance(["#{mode}/#{bin}"])
|
471
|
+
end
|
472
|
+
$AKRO_TESTS.each do |test|
|
473
|
+
test_dep =
|
474
|
+
if !test.binary.nil?
|
475
|
+
"#{mode}/#{test.binary}"
|
476
|
+
else
|
477
|
+
# map_script_to_exe may return nil, which is fine
|
478
|
+
FileMapper.map_script_to_exe(test.script)
|
479
|
+
end
|
480
|
+
task "#{test.name}_test_#{mode}" => test_dep do |task|
|
481
|
+
puts "Running test #{task.name}"
|
482
|
+
base = (if !test.script.nil? then "#{test.script}" else "#{mode}/#{test.binary}" end)
|
483
|
+
params = (if !test.cmdline.nil? then " " + test.cmdline else "" end)
|
484
|
+
new_ld_path = if ENV.has_key?("LD_LIBRARY_PATH") then "#{mode}/:#{ENV['LD_LIBRARY_PATH']}" else "#{mode}/" end
|
485
|
+
system({"MODE" => mode, "LD_LIBRARY_PATH" => new_ld_path}, base + params) do |ok, res|
|
486
|
+
raise "Test #{task.name} failed" if !ok
|
487
|
+
end
|
488
|
+
puts "Test #{task.name} passed"
|
489
|
+
end
|
490
|
+
Rake::Task["test_#{mode}"].enhance(["#{test.name}_test_#{mode}"])
|
491
|
+
end
|
492
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: akro
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vlad Petric
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '11.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '11.1'
|
27
|
+
description:
|
28
|
+
email: vlad@impaler.org
|
29
|
+
executables:
|
30
|
+
- akro
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- bin/akro
|
35
|
+
- lib/akro.rb
|
36
|
+
- lib/akrobuild.rake
|
37
|
+
homepage:
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
metadata: {}
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2.0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 2.5.1
|
58
|
+
signing_key:
|
59
|
+
specification_version: 4
|
60
|
+
summary: Akro build - an extreme C++ build system
|
61
|
+
test_files: []
|