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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e9bebbc3472c5f6271c4c019f23bf18779492934ed86411f4d09384e51bfeab
4
- data.tar.gz: 9aa82b75a58e0992653ddc5419bf14e129846cc54cc9358f08baa1d2014d8d5a
3
+ metadata.gz: f6650afffc9e3aa13bb3489b419cd7e4f2b44f1f104be6fdffa77d0b2a66d072
4
+ data.tar.gz: fef3df6c97065e9274c2f95e2b2993a740d46a563e9e04b7359fbb4b69d4f95d
5
5
  SHA512:
6
- metadata.gz: fd9be9cc303239eaa9853c177501e460023279a6385094afbe79e55b912257cebe72860633b53503dff96583a61aa88ea6034ce0e741e36f4fce8acce33c2496
7
- data.tar.gz: 6ee389790c8490d80ef9742e877fc0de8b13b6b74629361e68f363155c628a0dff1764d066f4608b0b7e7cef72f20b1775c2b214be487b4bdcf943ab1b985c3f
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.2.1
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
@@ -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
- @flags = flgs
11
+ @linking_flags = flgs.filter {|f| f.start_with? "-l"}
12
+ @compiling_flags = flgs - @linking_flags
6
13
  end
7
14
 
8
- def flags_as_str
9
- flags.join " "
15
+ def compiling_flags_as_str
16
+ @compiling_flags.join " "
10
17
  end
11
18
 
12
- def append_flag(flag)
13
- @flags << flag
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} #{flags_as_str} -c #{src}"
18
- system "#{name} -o #{out} #{flags_as_str} -c #{src}"
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
- libs = flags.select {|f| f.start_with?('-l')}
23
- puts "#{name} -o #{out} #{objs.join(" ")} #{libs.join(" ")}"
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
- libs = flags.select {|f| f.start_with?('-l')}
29
- puts "#{name} -shared -o #{out}.so #{objs.join(" ")} #{libs.join(" ")}"
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
@@ -1,5 +1,8 @@
1
1
  require 'json'
2
2
 
3
+ ##
4
+ # class ConfigReader
5
+ # Just read a json file
3
6
  class ConfigReader
4
7
  def self.extract_flags(file)
5
8
  abort_on_err("config file #{file} does not exsit") unless File.exists? file
@@ -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
- def self.open_file_and_write(filename, content)
3
- File.open(filename, "w") {|f|
4
- f.write(content)
5
- }
6
- end
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
- def self.create_lib_header(path, lib_name, suffix='hpp')
39
- open_file_and_write(
40
- "#{path}/#{lib_name}.#{suffix}",
41
- <<~DOC
42
- #ifndef __#{lib_name.upcase}__
43
- #define __#{lib_name.upcase}__
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
- #endif
46
- DOC
47
- )
48
- end
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
- def self.create_emacs_dir_local(path)
51
- open_file_and_write(
52
- "#{path}/.dir-locals.el",
53
- <<~DOC
54
- ((nil . ((company-clang-arguments . ("-I./src/components/"
55
- "-I./components/"))))
56
- (nil . ((company-c-headers-path-user . ("./src/components/"
57
- "./components/")))))
58
- DOC
59
- )
60
- end
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
- def self.create_cpp(filename, src_sfx='cpp', hdr_sfx='hpp')
63
- open_file_and_write(
64
- "#{filename}.#{src_sfx}",
65
- <<~DOC
66
- #include "#{filename}.#{hdr_sfx}"
67
- DOC
68
- )
69
- end
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
- def self.create_hpp(workspace, prefix, filename, hdr_sfx='hpp')
72
- open_file_and_write(
73
- "#{filename}.#{hdr_sfx}",
74
- <<~DOC
75
- #ifndef __#{workspace.upcase}__#{prefix.upcase}__#{filename.upcase}__
76
- #define __#{workspace.upcase}__#{prefix.upcase}__#{filename.upcase}__
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
- #endif
79
- DOC
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
@@ -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
@@ -1,3 +1,6 @@
1
+ ##
2
+ # class SourceFiles
3
+ # A simple class to assist collect all files or some files in a directory.
1
4
  class SourceFiles
2
5
  class << self
3
6
  def get_all(dir, &block)
@@ -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 files, args
241
- link_exectutable('./target', Dir.glob("obj/*.o"))
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.append_flag '-fPIC'
248
- build_common files, args
249
- link_shared('./target', Dir.glob("obj/*.o"))
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
- puts "compiling #{f}"
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
- puts "compiling #{f}"
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.2.4
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-06-24 00:00:00.000000000 Z
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.