akro 0.0.1

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