canoe 0.2.4 → 0.3.0
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 +4 -4
- data/lib/cmd.rb +8 -1
- data/lib/compiler.rb +27 -13
- data/lib/config_reader.rb +3 -0
- data/lib/default_files.rb +79 -73
- data/lib/dependence.rb +21 -1
- data/lib/source_files.rb +3 -0
- data/lib/workspace.rb +45 -13
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f6650afffc9e3aa13bb3489b419cd7e4f2b44f1f104be6fdffa77d0b2a66d072
|
|
4
|
+
data.tar.gz: fef3df6c97065e9274c2f95e2b2993a740d46a563e9e04b7359fbb4b69d4f95d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c093606ffcc64c3679afc3b8998841e7e1b8e83a2315d5bc8f1ad91e2c3b36d3eac5d649dda55d27287600ba52c9880c2f65b612b65f5fb57dbeac06ddc865b
|
|
7
|
+
data.tar.gz: 7483c43fa9d8f91c27be1b042f2b151187a867e85fd4cffc57f84b0a01c892583ef3f7d57ad6c816ad50668cabdfcb4e6c955db9c95aba8037ccf30c02eb0054
|
data/lib/cmd.rb
CHANGED
|
@@ -2,6 +2,9 @@ require_relative "workspace"
|
|
|
2
2
|
require_relative "err"
|
|
3
3
|
require_relative "config_reader"
|
|
4
4
|
|
|
5
|
+
##
|
|
6
|
+
# class CmdParser
|
|
7
|
+
# Parsing command arguments passed to canoe
|
|
5
8
|
class CmdParser
|
|
6
9
|
include Err
|
|
7
10
|
def initialize(options)
|
|
@@ -85,9 +88,13 @@ class CmdParser
|
|
|
85
88
|
get_current_workspace.clean
|
|
86
89
|
end
|
|
87
90
|
|
|
91
|
+
def parse_test(args)
|
|
92
|
+
get_current_workspace.test args
|
|
93
|
+
end
|
|
94
|
+
|
|
88
95
|
def parse_version(args)
|
|
89
96
|
puts <<~VER
|
|
90
|
-
canoe v0.
|
|
97
|
+
canoe v0.3.0
|
|
91
98
|
For features in this version, please visit https://github.com/Dicridon/canoe
|
|
92
99
|
Currently, canoe can do below:
|
|
93
100
|
- project creation
|
data/lib/compiler.rb
CHANGED
|
@@ -1,33 +1,47 @@
|
|
|
1
|
+
##
|
|
2
|
+
# class Compiler
|
|
3
|
+
# Storing compiler name in String and flags as an array
|
|
1
4
|
class Compiler
|
|
2
5
|
attr_reader :name, :flags
|
|
6
|
+
##
|
|
7
|
+
# @name: String
|
|
8
|
+
# @flgs: Array of String
|
|
3
9
|
def initialize(name, flgs)
|
|
4
10
|
@name = name
|
|
5
|
-
@
|
|
11
|
+
@linking_flags = flgs.filter {|f| f.start_with? "-l"}
|
|
12
|
+
@compiling_flags = flgs - @linking_flags
|
|
6
13
|
end
|
|
7
14
|
|
|
8
|
-
def
|
|
9
|
-
|
|
15
|
+
def compiling_flags_as_str
|
|
16
|
+
@compiling_flags.join " "
|
|
10
17
|
end
|
|
11
18
|
|
|
12
|
-
def
|
|
13
|
-
@
|
|
19
|
+
def linking_flags_as_str
|
|
20
|
+
@linking_flags.join " "
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def append_compiling_flag(flag)
|
|
25
|
+
@compiling_flags << flag
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def append_linking_flag(flag)
|
|
29
|
+
@linking_flags << flag
|
|
14
30
|
end
|
|
15
31
|
|
|
16
32
|
def compile(src, out)
|
|
17
|
-
puts "#{name} -o #{out} #{
|
|
18
|
-
system "#{name} -o #{out} #{
|
|
33
|
+
puts "#{name} -o #{out} #{compiling_flags_as_str} -c #{src}"
|
|
34
|
+
system "#{name} -o #{out} #{compiling_flags_as_str} -c #{src}"
|
|
19
35
|
end
|
|
20
36
|
|
|
21
37
|
def link_executable(out, objs)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
system "#{name} -o #{out} #{objs.join(" ")} #{libs.join(" ")}"
|
|
38
|
+
puts "#{name} -o #{out} #{objs.join(" ")} #{linking_flags_as_str}"
|
|
39
|
+
system "#{name} -o #{out} #{objs.join(" ")} #{linking_flags_as_str}"
|
|
25
40
|
end
|
|
26
41
|
|
|
27
42
|
def link_shared(out, objs)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
system "#{name} -shared -o #{out}.so #{objs.join(" ")} #{libs.join(" ")}"
|
|
43
|
+
puts "#{name} -shared -o #{out}.so #{objs.join(" ")} #{linking_flags_as_str}"
|
|
44
|
+
system "#{name} -shared -o #{out}.so #{objs.join(" ")} #{linking_flags_as_str}"
|
|
31
45
|
end
|
|
32
46
|
|
|
33
47
|
def inspect
|
data/lib/config_reader.rb
CHANGED
data/lib/default_files.rb
CHANGED
|
@@ -1,82 +1,88 @@
|
|
|
1
|
+
##
|
|
2
|
+
# class DefaultFiles
|
|
3
|
+
# A singleton class to generate header and souce files.
|
|
4
|
+
# TODO: consider using class source_file.rb in Pareater
|
|
1
5
|
class DefaultFiles
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def self.create_config(path, src_sfx='cpp', hdr_sfx='hpp')
|
|
9
|
-
open_file_and_write(
|
|
10
|
-
"#{path}/config.json",
|
|
11
|
-
<<~CONFIG
|
|
12
|
-
{
|
|
13
|
-
"compiler": "clang++",
|
|
14
|
-
"header-suffix": "#{hdr_sfx}",
|
|
15
|
-
"source-suffix": "#{src_sfx}",
|
|
16
|
-
"flags": {
|
|
17
|
-
"opt": "-O2",
|
|
18
|
-
"debug": "-g",
|
|
19
|
-
"std": "-std=c++17"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
CONFIG
|
|
23
|
-
)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.create_main(path, suffix='cpp')
|
|
27
|
-
open_file_and_write(
|
|
28
|
-
"#{path}/main.#{suffix}",
|
|
29
|
-
<<~DOC
|
|
30
|
-
#include <iostream>
|
|
31
|
-
int main(int argc, char *argv[]) {
|
|
32
|
-
std::cout << "hello world!" << std::endl;
|
|
33
|
-
}
|
|
34
|
-
DOC
|
|
35
|
-
)
|
|
36
|
-
end
|
|
6
|
+
class << self
|
|
7
|
+
def open_file_and_write(filename, content)
|
|
8
|
+
File.open(filename, "w") {|f|
|
|
9
|
+
f.write(content)
|
|
10
|
+
}
|
|
11
|
+
end
|
|
37
12
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
13
|
+
def create_config(path, src_sfx='cpp', hdr_sfx='hpp')
|
|
14
|
+
open_file_and_write(
|
|
15
|
+
"#{path}/config.json",
|
|
16
|
+
<<~CONFIG
|
|
17
|
+
{
|
|
18
|
+
"compiler": "clang++",
|
|
19
|
+
"header-suffix": "#{hdr_sfx}",
|
|
20
|
+
"source-suffix": "#{src_sfx}",
|
|
21
|
+
"flags": {
|
|
22
|
+
"opt": "-O2",
|
|
23
|
+
"debug": "-g",
|
|
24
|
+
"std": "-std=c++17"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
CONFIG
|
|
28
|
+
)
|
|
29
|
+
end
|
|
44
30
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
31
|
+
def create_main(path, suffix='cpp')
|
|
32
|
+
open_file_and_write(
|
|
33
|
+
"#{path}/main.#{suffix}",
|
|
34
|
+
<<~DOC
|
|
35
|
+
#include <iostream>
|
|
36
|
+
int main(int argc, char *argv[]) {
|
|
37
|
+
std::cout << "hello world!" << std::endl;
|
|
38
|
+
}
|
|
39
|
+
DOC
|
|
40
|
+
)
|
|
41
|
+
end
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
43
|
+
def create_lib_header(path, lib_name, suffix='hpp')
|
|
44
|
+
open_file_and_write(
|
|
45
|
+
"#{path}/#{lib_name}.#{suffix}",
|
|
46
|
+
<<~DOC
|
|
47
|
+
#ifndef __#{lib_name.upcase}__
|
|
48
|
+
#define __#{lib_name.upcase}__
|
|
49
|
+
|
|
50
|
+
#endif
|
|
51
|
+
DOC
|
|
52
|
+
)
|
|
53
|
+
end
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
open_file_and_write(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
55
|
+
# def create_emacs_dir_local(path)
|
|
56
|
+
# open_file_and_write(
|
|
57
|
+
# "#{path}/.dir-locals.el",
|
|
58
|
+
# <<~DOC
|
|
59
|
+
# ((nil . ((company-clang-arguments . ("-I./src/components/"
|
|
60
|
+
# "-I./components/"))))
|
|
61
|
+
# (nil . ((company-c-headers-path-user . ("./src/components/"
|
|
62
|
+
# "./components/")))))
|
|
63
|
+
# DOC
|
|
64
|
+
# )
|
|
65
|
+
# end
|
|
70
66
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
def create_cpp(filename, src_sfx='cpp', hdr_sfx='hpp')
|
|
68
|
+
open_file_and_write(
|
|
69
|
+
"#{filename}.#{src_sfx}",
|
|
70
|
+
<<~DOC
|
|
71
|
+
#include "#{filename}.#{hdr_sfx}"
|
|
72
|
+
DOC
|
|
73
|
+
)
|
|
74
|
+
end
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
def create_hpp(workspace, prefix, filename, hdr_sfx='hpp')
|
|
77
|
+
open_file_and_write(
|
|
78
|
+
"#{filename}.#{hdr_sfx}",
|
|
79
|
+
<<~DOC
|
|
80
|
+
#ifndef __#{workspace.upcase}__#{prefix.upcase}__#{filename.upcase}__
|
|
81
|
+
#define __#{workspace.upcase}__#{prefix.upcase}__#{filename.upcase}__
|
|
82
|
+
|
|
83
|
+
#endif
|
|
84
|
+
DOC
|
|
85
|
+
)
|
|
86
|
+
end
|
|
81
87
|
end
|
|
82
88
|
end
|
data/lib/dependence.rb
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
require_relative 'source_files'
|
|
2
2
|
require_relative 'err'
|
|
3
3
|
|
|
4
|
+
##
|
|
5
|
+
# class DepAnalyzer
|
|
6
|
+
# This class is the key component of canoe, which offers file dependency analysis functionality.
|
|
7
|
+
# A DepAnalyzer takes a directory as input, sources files and corresponding header files in this
|
|
8
|
+
# directory should have same name, i.e. test.cpp and test.hpp.
|
|
9
|
+
# DepAnalyzer would read every source file and recursively process user header files included in this source file to
|
|
10
|
+
# find out all user header files this source file depends on.
|
|
11
|
+
# Based on dependencies built in previous stage, DepAnalyzer determines which files should be recompiled and return
|
|
12
|
+
# these files to caller.
|
|
13
|
+
#
|
|
14
|
+
# Dependencies could be written to a file to avoid wasting time parsing all files, Depanalyzer would read from
|
|
15
|
+
# this file to construct dependencies. But if sources files included new headers or included headers are revmoed,
|
|
16
|
+
# Depanalyzer should rebuild the whole dependencies.
|
|
4
17
|
class DepAnalyzer
|
|
5
18
|
include Err
|
|
6
19
|
def self.read_from(filename)
|
|
@@ -16,11 +29,16 @@ class DepAnalyzer
|
|
|
16
29
|
end
|
|
17
30
|
|
|
18
31
|
def self.compiling_filter(deps, build_time, src_sfx='cpp', hdr_sfx='hpp')
|
|
19
|
-
files = []
|
|
32
|
+
files = []
|
|
33
|
+
@processed = {}
|
|
34
|
+
deps.keys.each do |k|
|
|
35
|
+
@processed[k] = false
|
|
36
|
+
end
|
|
20
37
|
deps.each do |k, v|
|
|
21
38
|
next if k.end_with? ".#{hdr_sfx}"
|
|
22
39
|
if should_recompile?(k, build_time)
|
|
23
40
|
files << k
|
|
41
|
+
@processed[k] = true
|
|
24
42
|
next
|
|
25
43
|
end
|
|
26
44
|
v.each do |f|
|
|
@@ -40,6 +58,8 @@ class DepAnalyzer
|
|
|
40
58
|
return true
|
|
41
59
|
else
|
|
42
60
|
deps[file].each do |f|
|
|
61
|
+
next if @processed[f]
|
|
62
|
+
@processed[f] = true
|
|
43
63
|
return true if mark(f, build_time, deps)
|
|
44
64
|
end
|
|
45
65
|
end
|
data/lib/source_files.rb
CHANGED
data/lib/workspace.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'fileutils'
|
|
2
|
-
require 'open3'
|
|
3
2
|
require_relative 'source_files'
|
|
4
3
|
require_relative 'compiler'
|
|
5
4
|
require_relative 'config_reader'
|
|
@@ -84,7 +83,7 @@ class WorkSpace
|
|
|
84
83
|
|
|
85
84
|
def initialize(name, mode, src_suffix='cpp', hdr_suffix='hpp')
|
|
86
85
|
@name = name
|
|
87
|
-
@compiler = Compiler.new 'clang++', '-Isrc/components'
|
|
86
|
+
@compiler = Compiler.new 'clang++', ['-Isrc/components']
|
|
88
87
|
@cwd = Dir.new(Dir.pwd)
|
|
89
88
|
@workspace = "#{Dir.pwd}/#{@name}"
|
|
90
89
|
@src = "#{@workspace}/src"
|
|
@@ -92,6 +91,7 @@ class WorkSpace
|
|
|
92
91
|
@obj = "#{@workspace}/obj"
|
|
93
92
|
@third = "#{@workspace}/third-party"
|
|
94
93
|
@target = "#{@workspace}/target"
|
|
94
|
+
@tests = "#{@workspace}/tests"
|
|
95
95
|
@mode = mode
|
|
96
96
|
@deps = '.canoe.deps'
|
|
97
97
|
|
|
@@ -115,10 +115,13 @@ class WorkSpace
|
|
|
115
115
|
end
|
|
116
116
|
File.new("#{@workspace}/.canoe", "w")
|
|
117
117
|
DefaultFiles.create_config @workspace, @source_suffix, @header_suffix
|
|
118
|
-
DefaultFiles.create_emacs_dir_local @workspace
|
|
118
|
+
# DefaultFiles.create_emacs_dir_local @workspace
|
|
119
119
|
|
|
120
120
|
Dir.mkdir(@third)
|
|
121
121
|
Dir.mkdir(@target)
|
|
122
|
+
Dir.chdir(@workspace) do
|
|
123
|
+
system "git init"
|
|
124
|
+
end
|
|
122
125
|
puts "workspace #{@workspace} is created"
|
|
123
126
|
end
|
|
124
127
|
|
|
@@ -189,6 +192,17 @@ class WorkSpace
|
|
|
189
192
|
end
|
|
190
193
|
end
|
|
191
194
|
end
|
|
195
|
+
|
|
196
|
+
def test(args)
|
|
197
|
+
args.each do |arg|
|
|
198
|
+
case arg
|
|
199
|
+
when "all"
|
|
200
|
+
test_all
|
|
201
|
+
else
|
|
202
|
+
test_single arg
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
192
206
|
|
|
193
207
|
private
|
|
194
208
|
def create_working_files(prefix, filename)
|
|
@@ -227,45 +241,63 @@ class WorkSpace
|
|
|
227
241
|
end
|
|
228
242
|
|
|
229
243
|
def link_exectutable(odir, objs)
|
|
244
|
+
puts "[100%] linking"
|
|
230
245
|
@compiler.link_executable "#{odir}/#{@name}", objs
|
|
231
246
|
end
|
|
232
247
|
|
|
233
248
|
def link_shared(odir, objs)
|
|
249
|
+
puts "[100%] linking"
|
|
234
250
|
@compiler.link_shared "#{odir}/lib#{@name}", objs
|
|
235
251
|
end
|
|
236
252
|
|
|
237
253
|
def build_bin(files, args)
|
|
238
254
|
return if files.empty?
|
|
239
255
|
build_compiler_from_config args
|
|
240
|
-
build_common
|
|
241
|
-
|
|
256
|
+
if build_common(files, args)
|
|
257
|
+
link_exectutable('./target', Dir.glob("obj/*.o"))
|
|
258
|
+
puts "canoe: building succeeded"
|
|
259
|
+
else
|
|
260
|
+
puts "canoe: building failed"
|
|
261
|
+
end
|
|
242
262
|
end
|
|
243
263
|
|
|
244
264
|
def build_lib(files, args)
|
|
245
265
|
return if files.empty?
|
|
246
266
|
build_compiler_from_config args
|
|
247
|
-
@compiler.
|
|
248
|
-
build_common files, args
|
|
249
|
-
|
|
267
|
+
@compiler.append_compiling_flag '-fPIC'
|
|
268
|
+
if (build_common files, args)
|
|
269
|
+
link_shared('./target', Dir.glob("obj/*.o"))
|
|
270
|
+
puts "canoe: building succeeded"
|
|
271
|
+
else
|
|
272
|
+
puts "canoe: building failed"
|
|
273
|
+
end
|
|
250
274
|
end
|
|
251
275
|
|
|
252
276
|
def build_common(files, args)
|
|
277
|
+
all = SourceFiles.get_all('./src') {|f| f.end_with? @source_suffix}
|
|
278
|
+
total = all.size.to_f
|
|
279
|
+
compiled = total - files.size
|
|
253
280
|
comps = files.select {|f| f.start_with? @components_prefix}
|
|
254
281
|
srcs = files - comps
|
|
255
|
-
|
|
282
|
+
flag = true;
|
|
256
283
|
srcs.each do |f|
|
|
257
|
-
|
|
284
|
+
progress = (compiled / total).round(2) * 100
|
|
285
|
+
printf "[#{progress.to_i}%%] compiling #{f}: "
|
|
258
286
|
fname = f.split("/")[-1]
|
|
259
287
|
o = @obj_prefix + fname.delete_suffix(File.extname(fname)) + '.o'
|
|
260
|
-
compile f, o
|
|
288
|
+
flag = false unless compile f, o
|
|
289
|
+
compiled += 1
|
|
261
290
|
end
|
|
262
291
|
|
|
263
292
|
comps.each do |f|
|
|
264
|
-
|
|
293
|
+
progress = (compiled / total).round(2) * 100
|
|
294
|
+
printf "[#{progress.to_i}%%] compiling #{f}: "
|
|
265
295
|
o = @obj_prefix + f.delete_suffix(File.extname(f))[@components_prefix.length..]
|
|
266
296
|
.gsub('/', '_') + '.o'
|
|
267
|
-
compile f, o
|
|
297
|
+
flag = false unless compile f, o
|
|
298
|
+
compiled += 1
|
|
268
299
|
end
|
|
300
|
+
flag
|
|
269
301
|
end
|
|
270
302
|
|
|
271
303
|
def clean_obj
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: canoe
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- XIONG Ziwei
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-07-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: |+
|
|
14
14
|
Canoe offers project management and building facilities to C/C++ projects.
|