canoe 0.3.2.1 → 0.3.3

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: f216d0dc37bc62674772eb685e40bae7859af341e75f3b67e4f9327030ad3483
4
- data.tar.gz: 28c69b2037f47926b86a5f927ff0398f6122a30adb725ce0e5830dea81acf549
3
+ metadata.gz: 6c8e08b29045ffc655f4dedf9cb358b70e643702dac79a88d81436e39ba9ace1
4
+ data.tar.gz: 2d5a877f870fa531b236f570c52f3b97ec9fc7efd35c0b05447f1e7e850f47e1
5
5
  SHA512:
6
- metadata.gz: 110c69c11e3be4d7d38e23cb2d83680fd4677f5537f5448fba4a5d68999e5e1727794d9c857ccb290a628e6c4586c22a68c8ee73799f7ecf1e58ffa9dd1ea351
7
- data.tar.gz: 05a9808ee35431a874a932c36af3b6ab3d5f0734a04fd2ed70aa9d18ac2a4d3c211340142f722acee9dea997030b80c5e34e77491c6a387ab1bad74936529e7e
6
+ metadata.gz: a40625eaafec1023609c210a5d84710433b3d34557fc1079b9a0ca441da60ecfc6316ab4d9e1c40991530c6fb8c49155109561f3663699dfffe3bd23cf6e1c44
7
+ data.tar.gz: 47fde1b6a149e118d6b835e2d82e55654627a08c98faa2a8535a9e142f29a2eda5b0572da9f43c13084932e70777502df48cd608ac2db27f8586c0538acab5a2
data/lib/cmd.rb CHANGED
@@ -53,31 +53,38 @@ module Canoe
53
53
  abort_on_err "it's not reasonable to add a component with no name given"
54
54
  end
55
55
 
56
- get_current_workspace.add args
56
+ current_workspace.add args
57
57
  end
58
58
 
59
59
  def parse_build(args)
60
- get_current_workspace.build args
60
+ options = {[] => 'target', ['all'] => 'all', ['test'] => 'test', ['base'] => 'base'}
61
+ abort_on_err "Unkown subcommand #{args.join(" ").red}" unless options.include?(args)
62
+ current_workspace.build options[args]
61
63
  end
62
64
 
63
65
  def parse_generate(args)
64
- get_current_workspace.generate
66
+ current_workspace.generate
65
67
  end
66
68
 
67
69
  def parse_run(args)
68
- get_current_workspace.run args
70
+ current_workspace.run args
69
71
  end
70
72
 
71
73
  def parse_dep(args)
72
- get_current_workspace.dep
74
+ current_workspace.dep
73
75
  end
74
76
 
75
77
  def parse_clean(args)
76
- get_current_workspace.clean args
78
+ options = {
79
+ [] => 'all', ['all'] => 'all',
80
+ ['target'] => 'target', ['tests'] => 'tests', ['obj'] => 'obj'
81
+ }
82
+ abort_on_err "Unkown subcommand #{args.join(" ").red}" unless options.include?(args)
83
+ current_workspace.clean options[args]
77
84
  end
78
85
 
79
86
  def parse_test(args)
80
- get_current_workspace.test args
87
+ current_workspace.test args
81
88
  end
82
89
 
83
90
  def parse_version(args)
@@ -89,11 +96,11 @@ module Canoe
89
96
  end
90
97
 
91
98
  def parse_update(args)
92
- get_current_workspace.update
99
+ current_workspace.update
93
100
  end
94
101
 
95
102
  def parse_make(args)
96
- get_current_workspace.make
103
+ current_workspace.make
97
104
  end
98
105
  end
99
106
  end
data/lib/config_reader.rb CHANGED
@@ -1,11 +1,17 @@
1
1
  require 'json'
2
+ require_relative 'util'
2
3
 
3
4
  ##
4
5
  # class ConfigReader
5
6
  # Just read a json file
6
7
  class ConfigReader
7
- def self.extract_flags(file)
8
- abort_on_err("config file #{file} does not exsit") unless File.exist? file
9
- JSON.parse(File.read(file))
8
+ include Canoe::Err
9
+ def initialize(file)
10
+ @config_file = file
11
+ end
12
+
13
+ def extract_flags
14
+ abort_on_err("config file #{@config_file} does not exsit") unless File.exist? @config_file
15
+ JSON.parse(File.read(@config_file))
10
16
  end
11
17
  end
data/lib/default_files.rb CHANGED
@@ -10,19 +10,18 @@ class DefaultFiles
10
10
  end
11
11
  end
12
12
 
13
- def create_config(path, src_sfx = 'cpp', hdr_sfx = 'hpp')
13
+ def create_config(path, compiler = 'clang++', src_sfx = 'cpp', hdr_sfx = 'hpp')
14
14
  open_file_and_write(
15
15
  "#{path}/config.json",
16
16
  <<~CONFIG
17
17
  {
18
- "compiler": "clang++",
18
+ "compiler": "#{compiler}",
19
19
  "header-suffix": "#{hdr_sfx}",
20
20
  "source-suffix": "#{src_sfx}",
21
21
  "flags": {
22
22
  "compile": {
23
23
  "opt": "-O2",
24
- "debug": "-g",
25
- "std": "-std=c++17"
24
+ "debug": "-g"
26
25
  },
27
26
  "link": {
28
27
 
@@ -34,12 +33,13 @@ class DefaultFiles
34
33
  end
35
34
 
36
35
  def create_main(path, suffix = 'cpp')
36
+ header = suffix == 'c' ? 'stdio.h' : 'iostream'
37
37
  open_file_and_write(
38
38
  "#{path}/main.#{suffix}",
39
39
  <<~DOC
40
- #include <iostream>
40
+ #include <#{header}>
41
41
  int main(int argc, char *argv[]) {
42
- std::cout << "hello world!" << std::endl;
42
+
43
43
  }
44
44
  DOC
45
45
  )
data/lib/source_files.rb CHANGED
@@ -30,13 +30,14 @@ class SourceFiles
30
30
  def get_all_helper(dir, &block)
31
31
  Dir.each_child(dir) do |f|
32
32
  file = "#{dir}/#{f}"
33
+ # we don't handle symlinks
33
34
  if File.file? file
34
35
  if block_given?
35
36
  @files << "#{file}" if yield(f)
36
37
  else
37
38
  @files << "#{file}"
38
39
  end
39
- else
40
+ elsif File.directory? file
40
41
  get_all_helper("#{file}", &block)
41
42
  end
42
43
  end
data/lib/util.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  require_relative 'coloring'
2
2
 
3
+ require 'English'
4
+
3
5
  module Canoe
6
+ ##
7
+ # Stepper record the progress of a task
8
+ # progress is obtained via #'progress_as_str
4
9
  class Stepper
5
10
  def initialize(total, togo)
6
11
  @total = total.to_f
@@ -16,13 +21,13 @@ module Canoe
16
21
  @togo -= 1 if @togo.positive?
17
22
  end
18
23
  end
19
-
24
+
20
25
  ##
21
26
  # wrapping workspace related functionality to expose to other modules
22
27
  module WorkSpaceUtil
23
- def get_current_workspace
28
+ def current_workspace
24
29
  abort_on_err 'not in a canoe workspace' unless File.exist? '.canoe'
25
- config = ConfigReader.extract_flags('config.json')
30
+ config = ConfigReader.new('config.json').extract_flags
26
31
 
27
32
  src_sfx = config['source-suffix'] || 'cpp'
28
33
  hdr_sfx = config['header-suffix'] || 'hpp'
@@ -34,30 +39,37 @@ module Canoe
34
39
  end
35
40
 
36
41
  def src_to_obj(src)
37
- get_current_workspace.src_to_obj(src)
42
+ current_workspace.src_to_obj(src)
38
43
  end
39
44
 
40
45
  def comp_to_obj(comp)
41
- get_current_workspace.comp_to_obj(comp)
46
+ current_workspace.comp_to_obj(comp)
42
47
  end
43
48
 
44
49
  def file_to_obj(file)
45
- get_current_workspace.file_to_obj(file)
50
+ current_workspace.file_to_obj(file)
46
51
  end
47
52
 
48
53
  def extract_one_file(file, deps)
49
- get_current_workspace.extract_one_file(file, deps)
54
+ current_workspace.extract_one_file(file, deps)
50
55
  end
51
56
 
52
57
  def extract_one_file_obj(file, deps)
53
- get_current_workspace.extract_one_file_obj(file, deps)
58
+ current_workspace.extract_one_file_obj(file, deps)
54
59
  end
55
60
  end
56
61
 
57
62
  module SystemCommand
58
63
  def issue_command(cmd_str)
59
64
  puts cmd_str
60
- system cmd_str
65
+ system(cmd_str)
66
+ end
67
+
68
+ def run_command(cmd_str)
69
+ puts cmd_str
70
+ status = system(cmd_str)
71
+ puts $CHILD_STATUS unless status
72
+ status
61
73
  end
62
74
  end
63
75
 
@@ -1,3 +1,4 @@
1
+ require 'json'
1
2
  module Canoe
2
3
  class WorkSpace
3
4
  def src_to_obj(src)
@@ -17,15 +18,15 @@ module Canoe
17
18
  end
18
19
  end
19
20
 
21
+ def hdr_of_src(file)
22
+ file.gsub(".#{@source_suffix}", ".#{@header_suffix}")
23
+ end
24
+
20
25
  # args are commandline parameters passed to `canoe build`,
21
- # could be 'all', 'test', 'target' or empty
22
- def build(args)
23
- options = {[] => 'target', ['all'] => 'all', ['test'] => 'test'}
24
- if options.include?(args)
25
- send "build_#{options[args]}"
26
- else
27
- abort_on_err "Unkown subcommand #{args.join(" ").red}"
28
- end
26
+ # could be 'all', 'test', 'target', 'base' or empty
27
+ def build(arg = 'target')
28
+ build_compiler_from_config
29
+ send "build_#{arg}"
29
30
  end
30
31
 
31
32
  private
@@ -46,14 +47,14 @@ module Canoe
46
47
  end
47
48
 
48
49
  def build_compiler_from_config
49
- flags = ConfigReader.extract_flags "config.json"
50
- compiler_name = flags["compiler"] ? flags["compiler"] : "clang++"
50
+ flags = ConfigReader.new('config.json').extract_flags
51
+ compiler_name = flags['compiler'] ? flags['compiler'] : 'clang++'
51
52
 
52
53
  abort_on_err "compiler #{compiler_name} not found" unless system "which #{compiler_name} > /dev/null"
53
- compiler_flags = ["-Isrc/components"]
54
+ compiler_flags = ['-Isrc/components']
54
55
  linker_flags = []
55
56
 
56
- c_flags, l_flags = flags["flags"]["compile"], flags["flags"]["link"]
57
+ c_flags, l_flags = flags['flags']['compile'], flags['flags']['link']
57
58
  build_flags(compiler_flags, c_flags)
58
59
  build_flags(linker_flags, l_flags)
59
60
 
@@ -132,12 +133,9 @@ module Canoe
132
133
 
133
134
  def build_target
134
135
  puts "#{'[BUILDING TARGET]'.magenta}..."
135
- deps = get_deps @deps, @src, [@src_short, @components_short]
136
136
  target = "#{@target}/#{@name}"
137
137
  build_time = File.exist?(target) ? File.mtime(target) : Time.new(0)
138
- files = DepAnalyzer.compiling_filter deps, build_time, @source_suffix, @header_suffix
139
-
140
- build_compiler_from_config
138
+ files = DepAnalyzer.compiling_filter target_deps, build_time, @source_suffix, @header_suffix
141
139
 
142
140
  if files.empty? && File.exist?(target)
143
141
  puts "nothing to do, all up to date"
@@ -146,5 +144,49 @@ module Canoe
146
144
 
147
145
  self.send "build_#{@mode.to_s}", files
148
146
  end
147
+
148
+ # generate a compile_commands.json file
149
+ def build_base
150
+ deps = target_deps.merge tests_deps
151
+ database = CompilationDatabase.new
152
+ deps.each_key do |k|
153
+ next if k.end_with? @header_suffix
154
+ c = @compiler.name.end_with?('++') ? 'c++' : 'c'
155
+
156
+ arg = [c] + @compiler.compiling_flags_as_str.split + [k] + [file_to_obj(k)] + ['-c', '-o']
157
+ database.add_command_object(@workspace, arg, k)
158
+ end
159
+ File.open('compile_commands.json', 'w') do |f|
160
+ f.puts database.pretty_to_s
161
+ end
162
+ end
163
+ end
164
+
165
+ class CompilationDatabase
166
+ attr_reader :database
167
+ def initialize
168
+ @database = []
169
+ end
170
+
171
+ def add_command_object(dir, arguments, file)
172
+ temp = {
173
+ "arguments" => arguments,
174
+ "directory" => dir,
175
+ "file" => file
176
+ }
177
+ @database << temp
178
+ end
179
+
180
+ def to_s
181
+ @database.to_s
182
+ end
183
+
184
+ def pretty_to_s
185
+ JSON.pretty_generate(@database)
186
+ end
187
+
188
+ def to_json
189
+ @database.to_json
190
+ end
149
191
  end
150
192
  end
@@ -1,16 +1,8 @@
1
1
  module Canoe
2
2
  class WorkSpace
3
3
  # valid options: none, 'all', 'target', 'tests'
4
- def clean(args)
5
- options = {
6
- [] => 'all', ['all'] => 'all',
7
- ['target'] => 'target', ['tests'] => 'tests', ['obj'] => 'obj'
8
- }
9
- if options.include?(args)
10
- send "clean_#{options[args]}"
11
- else
12
- abort_on_err "Unkown subcommand #{args.join(' ').red}"
13
- end
4
+ def clean(arg = 'all')
5
+ send "clean_#{arg}"
14
6
  end
15
7
 
16
8
  private
@@ -53,9 +53,10 @@ module Canoe
53
53
  build [all|test]:
54
54
  build current project, 'all' builds both target and tests, 'test' builds tests only
55
55
 
56
- test [tests]:
56
+ test [tests] [args]:
57
57
  build and run tests
58
58
  [tests]: 'all' for all tests, or a name of a test for a single test
59
+ [args]: args are passed to the single test
59
60
 
60
61
  run [options]:
61
62
  build current project with no specific compilation flags, and run this project, passing [options] as command line arguments to the binary
@@ -1,6 +1,8 @@
1
1
  # If the project has circular dependency, this command would fail
2
2
  module Canoe
3
- class Makefile
3
+ ##
4
+ # CanoeMakefile is used to offer makefile generation utilities
5
+ class CanoeMakefile
4
6
  include WorkSpaceUtil
5
7
  def initialize(workspace)
6
8
  @workspace = workspace
@@ -208,25 +210,23 @@ module Canoe
208
210
 
209
211
  def make_obj_rules(makefile, deps)
210
212
  cmplr = cxx?(get_compiler) ? 'CXX' : 'CC'
211
- makefile.puts("all: OUT\n")
212
- makefile.puts ''
213
213
 
214
214
  @all_names.each do |n|
215
- makefile.puts("$(OBJ_#{n}): $(#{n}_DEP)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $@ -c $(SRC_#{n})")
216
- makefile.puts ''
215
+ makefile.puts("$(OBJ_#{n}): $(#{n}_DEP)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $@ -c $(SRC_#{n})\n\n")
217
216
  end
218
-
219
217
  end
220
218
 
221
219
  def make_out_rules(makefile, deps)
222
220
  cmplr = cxx?(get_compiler) ? 'CXX' : 'CC'
223
221
  if @workspace.mode == :bin
224
- makefile.puts("OUT: $(OUT_OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $(TARGET) $(OUT_OBJS) $(LDFLAGS) $(LDLIBS)")
222
+ makefile.puts("out: $(OUT_OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $(TARGET) $(OUT_OBJS) $(LDFLAGS) $(LDLIBS)")
225
223
  else
226
- makefile.puts("OUT: $(OUT_OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -shared -o $(TARGET) $(OUT_OBJS) -fPIC $(LDFLAGS) $(LDLIBS)")
224
+ makefile.puts("out: $(OUT_OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -shared -o $(TARGET) $(OUT_OBJS) -fPIC $(LDFLAGS) $(LDLIBS)")
227
225
  end
228
226
  makefile.puts ''
229
227
  makefile.puts("test: $(TESTS)")
228
+ makefile.puts ''
229
+ makefile.puts("all: out test")
230
230
  end
231
231
 
232
232
  def make_tests_rules(makefile, deps)
@@ -256,10 +256,9 @@ module Canoe
256
256
  def make_rules(makefile, deps)
257
257
  make_dependencies makefile, deps
258
258
  makefile.puts ''
259
- make_obj_rules makefile, deps
260
- makefile.puts ''
261
259
  make_out_rules makefile, deps
262
260
  makefile.puts ''
261
+ make_obj_rules makefile, deps
263
262
  make_tests_rules makefile, deps
264
263
  makefile.puts ''
265
264
  make_clean makefile
@@ -268,11 +267,11 @@ module Canoe
268
267
 
269
268
  class WorkSpace
270
269
  def make
271
- config = ConfigReader.extract_flags "config.json"
270
+ config = ConfigReader.new('config.json').extract_flags
272
271
 
273
272
  deps = target_deps.merge tests_deps
274
273
 
275
- makefile = Makefile.new self
274
+ makefile = CanoeMakefile.new self
276
275
  makefile.configure config
277
276
  makefile.make! deps
278
277
  end
data/lib/workspace/new.rb CHANGED
@@ -8,24 +8,36 @@ module Canoe
8
8
  end
9
9
  Dir.mkdir(@src)
10
10
  Dir.mkdir(@components)
11
- Dir.mkdir("#{@workspace}/obj")
11
+ Dir.mkdir(@obj)
12
+ add_gitignore @obj
12
13
  if @mode == :bin
13
14
  DefaultFiles.create_main(@src, @source_suffix)
14
15
  else
15
16
  DefaultFiles.create_lib_header(@src, @name, @header_suffix)
16
17
  end
17
18
  File.new("#{@workspace}/.canoe", 'w')
18
- DefaultFiles.create_config @workspace, @source_suffix, @header_suffix
19
- # DefaultFiles.create_emacs_dir_local @workspace
19
+ compiler = @source_suffix == 'c' ? 'clang' : 'clang++'
20
+ DefaultFiles.create_config @workspace, compiler, @source_suffix, @header_suffix
20
21
 
21
22
  Dir.mkdir(@third)
22
23
  Dir.mkdir(@target)
24
+ add_gitignore @target
23
25
  Dir.mkdir(@tests)
24
26
  Dir.chdir(@workspace) do
25
- system 'git init'
26
- system 'canoe add tests'
27
+ issue_command 'git init'
28
+ issue_command 'canoe add tests'
27
29
  end
28
30
  puts "workspace #{@workspace.blue} is created"
29
31
  end
32
+
33
+ private
34
+
35
+ def add_gitignore(dir)
36
+ Dir.chdir(dir) do
37
+ File.open('.gitignore', 'w') do |f|
38
+ f.write "*\n!.gitignore\n"
39
+ end
40
+ end
41
+ end
30
42
  end
31
43
  end
data/lib/workspace/run.rb CHANGED
@@ -3,10 +3,10 @@ module Canoe
3
3
  def run(args)
4
4
  return if @mode == :lib
5
5
 
6
- return unless build []
6
+ return unless build
7
7
 
8
8
  args = args.join ' '
9
- issue_command "#{@target_short}/#{@name} #{args}"
9
+ run_command "#{@target_short}/#{@name} #{args}"
10
10
  end
11
11
  end
12
12
  end
@@ -5,15 +5,8 @@ module Canoe
5
5
  test_all
6
6
  return
7
7
  end
8
-
9
- args.each do |arg|
10
- case arg
11
- when 'all'
12
- test_all
13
- else
14
- test_single arg
15
- end
16
- end
8
+ # we don't handle spaces
9
+ test_single(args[0], args[1..].join(" "))
17
10
  end
18
11
 
19
12
  # extract one test file's dependency
@@ -44,13 +37,27 @@ module Canoe
44
37
  end
45
38
  end
46
39
 
47
- def test_single(name)
40
+ def test_single(name, args = "")
41
+ rebuild = false;
48
42
  bin = "#{@target_short}/test_#{name}"
43
+
44
+ rebuild ||= !File.exist?(bin)
45
+
49
46
  file = "#{@tests_short}/test_#{name}.#{@source_suffix}"
50
- abort_on_err "Can not find source file #{file.red} for test #{name.red}" unless File.exist?(file)
51
- build_one_test(file, fetch_all_deps) unless File.exist?(bin)
47
+ rebuild ||= File.mtime(bin) < File.mtime(file)
48
+
49
+ deps = fetch_all_deps
50
+ extract_one_file(file, deps).each do |f|
51
+ rebuild ||= File.mtime(bin) < File.mtime(f) || File.mtime(bin) < File.mtime(hdr_of_src(f))
52
+ end
52
53
 
53
- issue_command bin
54
+ cmd = "#{bin} #{args}"
55
+ if rebuild
56
+ build_compiler_from_config
57
+ run_command cmd if build_one_test(file, deps)
58
+ else
59
+ run_command cmd
60
+ end
54
61
  end
55
62
 
56
63
  def fetch_all_test_files
@@ -76,7 +83,7 @@ module Canoe
76
83
  def compile_one_test(test_file, deps)
77
84
  extract_one_file(test_file, deps).each do |f|
78
85
  o = file_to_obj(f)
79
- next if File.exist?(o) && File.mtime(o) > File.mtime(f)
86
+ next if File.exist?(o) && File.mtime(o) > File.mtime(f) && File.mtime(o) > File.mtime(hdr_of_src(f))
80
87
 
81
88
  compile(f, o)
82
89
  end
@@ -2,7 +2,7 @@ module Canoe
2
2
  class WorkSpace
3
3
  def self.version
4
4
  puts <<~VER
5
- canoe v0.3.2.1
5
+ canoe v0.3.3
6
6
  For features in this version, please visit https://github.com/Dicridon/canoe
7
7
  Currently, canoe can do below:
8
8
  - project creation
@@ -11,6 +11,8 @@ module Canoe
11
11
  ##
12
12
  # A workspace resents a C/C++ project
13
13
  # This class is responsible for the main functionality of canoe, such as building and cleaning
14
+ # TODO
15
+ # add a command to generate compile_commands.json so users won't have to install bear
14
16
  class WorkSpace
15
17
  include Err
16
18
  include SystemCommand
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.3.2.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - XIONG Ziwei
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-13 00:00:00.000000000 Z
11
+ date: 2021-08-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.