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.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/bin/akro +42 -0
  3. data/lib/akro.rb +135 -0
  4. data/lib/akrobuild.rake +492 -0
  5. 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
@@ -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: []