akro 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|