canoe 0.2.1 → 0.3.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.
- checksums.yaml +4 -4
- data/lib/canoe.rb +10 -1
- data/lib/cmd.rb +8 -1
- data/lib/coloring.rb +23 -0
- data/lib/compiler.rb +31 -11
- data/lib/config_reader.rb +3 -0
- data/lib/default_files.rb +79 -61
- data/lib/dependence.rb +33 -3
- data/lib/err.rb +4 -3
- data/lib/source_files.rb +3 -0
- data/lib/workspace.rb +90 -32
- metadata +13 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7c1916c0ee5ce05d67222c84f93ac7e41de04895ffb523b1a5435276c6f8e11f
|
|
4
|
+
data.tar.gz: f3b69717aed857c30f8154fb1f63126b8f84c42081890ef1be75c6d2a7250735
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: adae82066e778ae3756d970b75fb87784087e25996051c9cd5dd5ad75f265c09418eeb5c4387db9b0c9c125d1b1739461f1f0a0dfc72cde9f1914a65023eb030
|
|
7
|
+
data.tar.gz: 7d31ba373cf0a9a7f41178a153ee8fd7f9eb442a2698ec464c5ea9ca247b9816765f2bc17db1d0902209c6e6e4ff4bc238a4d7e9fa59cf74ba29a841bf519c3b
|
data/lib/canoe.rb
CHANGED
|
@@ -4,7 +4,16 @@ require_relative "source_files"
|
|
|
4
4
|
|
|
5
5
|
class Canoe
|
|
6
6
|
def initialize
|
|
7
|
-
options = [
|
|
7
|
+
options = ['new',
|
|
8
|
+
'add',
|
|
9
|
+
'build',
|
|
10
|
+
'generate',
|
|
11
|
+
'run',
|
|
12
|
+
'dep',
|
|
13
|
+
'clean',
|
|
14
|
+
'version',
|
|
15
|
+
'help',
|
|
16
|
+
'update']
|
|
8
17
|
@cmd = CmdParser.new options
|
|
9
18
|
end
|
|
10
19
|
|
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/coloring.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
##
|
|
2
|
+
# gem Colorize is a great tool, but I don't want add dependencies to Canoe
|
|
3
|
+
class String
|
|
4
|
+
def self.define_coloring_methods
|
|
5
|
+
colors = {
|
|
6
|
+
30 => :black,
|
|
7
|
+
31 => :red,
|
|
8
|
+
32 => :green,
|
|
9
|
+
33 => :yellow,
|
|
10
|
+
34 => :blue,
|
|
11
|
+
35 => :magenta,
|
|
12
|
+
36 => :cyan,
|
|
13
|
+
37 => :white
|
|
14
|
+
}
|
|
15
|
+
colors.each do |k, v|
|
|
16
|
+
define_method v do
|
|
17
|
+
"\033[#{k}m#{self}\033[0m"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
define_coloring_methods
|
|
23
|
+
end
|
data/lib/compiler.rb
CHANGED
|
@@ -1,29 +1,49 @@
|
|
|
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
|
-
def
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
system "#{name} -o #{out} #{objs.join(" ")} #{libs.join(" ")}"
|
|
37
|
+
def link_executable(out, objs)
|
|
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
|
|
|
42
|
+
def link_shared(out, objs)
|
|
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}"
|
|
45
|
+
end
|
|
46
|
+
|
|
27
47
|
def inspect
|
|
28
48
|
puts "compiler name: #{name.inspect}"
|
|
29
49
|
puts "compiler flags: #{flags.inspect}"
|
data/lib/config_reader.rb
CHANGED
data/lib/default_files.rb
CHANGED
|
@@ -1,70 +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
|
-
|
|
6
|
+
class << self
|
|
7
|
+
def open_file_and_write(filename, content)
|
|
8
|
+
File.open(filename, "w") do |f|
|
|
9
|
+
f.write(content)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
open_file_and_write(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
58
66
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|
65
75
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
69
87
|
end
|
|
70
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,19 @@ 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
|
+
@recompiles = {}
|
|
35
|
+
deps.keys.each do |k|
|
|
36
|
+
@processed[k] = false
|
|
37
|
+
@recompiles[k] = false
|
|
38
|
+
end
|
|
20
39
|
deps.each do |k, v|
|
|
21
40
|
next if k.end_with? ".#{hdr_sfx}"
|
|
22
41
|
if should_recompile?(k, build_time)
|
|
23
42
|
files << k
|
|
43
|
+
@processed[k] = true
|
|
44
|
+
@recompiles[k] = true
|
|
24
45
|
next
|
|
25
46
|
end
|
|
26
47
|
v.each do |f|
|
|
@@ -40,7 +61,12 @@ class DepAnalyzer
|
|
|
40
61
|
return true
|
|
41
62
|
else
|
|
42
63
|
deps[file].each do |f|
|
|
43
|
-
return
|
|
64
|
+
return @recompiles[f] if @processed[f]
|
|
65
|
+
@processed[f] = true
|
|
66
|
+
if mark(f, build_time, deps)
|
|
67
|
+
@recompiles[f] = true
|
|
68
|
+
return true
|
|
69
|
+
end
|
|
44
70
|
end
|
|
45
71
|
end
|
|
46
72
|
false
|
|
@@ -49,7 +75,11 @@ class DepAnalyzer
|
|
|
49
75
|
def self.should_recompile?(file, build_time)
|
|
50
76
|
judge = build_time
|
|
51
77
|
if build_time == Time.new(0)
|
|
52
|
-
objfile =
|
|
78
|
+
objfile = if file.start_with?("./src/components")
|
|
79
|
+
'./obj/' + file.delete_suffix(File.extname(file))['./src/components/'.length..].gsub('/', '_') + '.o'
|
|
80
|
+
else
|
|
81
|
+
"./obj/#{File.basename(file, ".*")}.o"
|
|
82
|
+
end
|
|
53
83
|
return true unless File.exists? objfile
|
|
54
84
|
judge = File.mtime(objfile)
|
|
55
85
|
end
|
data/lib/err.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
require_relative 'coloring'
|
|
1
2
|
module Err
|
|
2
3
|
def warn_on_err(err)
|
|
3
4
|
puts <<~ERR
|
|
4
|
-
|
|
5
|
+
#{"Waring: ".yellow}
|
|
5
6
|
#{err}
|
|
6
7
|
try 'canoe help' for more information
|
|
7
8
|
ERR
|
|
@@ -9,11 +10,11 @@ module Err
|
|
|
9
10
|
|
|
10
11
|
def abort_on_err(err)
|
|
11
12
|
abort <<~ERR
|
|
12
|
-
Fatal:
|
|
13
|
+
#{"Fatal: ".red}
|
|
13
14
|
#{err}
|
|
14
15
|
try 'canoe help' for more information
|
|
15
16
|
ERR
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
module_function :warn_on_err, :abort_on_err
|
|
19
|
-
end
|
|
20
|
+
end
|
data/lib/source_files.rb
CHANGED
data/lib/workspace.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
require 'fileutils'
|
|
2
|
-
require 'open3'
|
|
3
2
|
require_relative 'source_files'
|
|
4
3
|
require_relative 'compiler'
|
|
5
4
|
require_relative 'config_reader'
|
|
6
5
|
require_relative 'default_files'
|
|
7
6
|
require_relative 'err'
|
|
8
7
|
require_relative 'dependence'
|
|
8
|
+
require_relative 'coloring'
|
|
9
9
|
|
|
10
10
|
class WorkSpace
|
|
11
11
|
include Err
|
|
@@ -18,7 +18,9 @@ class WorkSpace
|
|
|
18
18
|
|
|
19
19
|
canoe build: compile current project (execute this command in project directory)
|
|
20
20
|
|
|
21
|
-
canoe generate: generate dependency
|
|
21
|
+
canoe generate: generate dependency relationships and store it in '.canoe.deps' file. Alias: update
|
|
22
|
+
|
|
23
|
+
canoe update: udpate dependency relationships and store it in '.canoe.deps' file.
|
|
22
24
|
|
|
23
25
|
canoe run: compile and execute current project (execute this command in project directory)
|
|
24
26
|
|
|
@@ -27,7 +29,8 @@ class WorkSpace
|
|
|
27
29
|
canoe help: show this help message
|
|
28
30
|
|
|
29
31
|
canoe add tada: add a folder named tada under workspace/components,
|
|
30
|
-
|
|
32
|
+
|
|
33
|
+
canoe dep: show current dependency relationships of current project
|
|
31
34
|
|
|
32
35
|
canoe verion: version information
|
|
33
36
|
|
|
@@ -38,11 +41,20 @@ class WorkSpace
|
|
|
38
41
|
|
|
39
42
|
[mode]: --lib for a library and --bin for executable binaries
|
|
40
43
|
[suffixes]: should be in 'source_suffix:header_suffix" format, notice the ':' between two suffixes
|
|
44
|
+
add component_name:
|
|
45
|
+
add a folder named tada under workspace/components.
|
|
46
|
+
two files tada.hpp and tada.cpp would be craeted and intialized. File suffix may differ according users' specifications.
|
|
47
|
+
if component_name is a path separated by '/', then canoe would create folders and corresponding files recursively.
|
|
41
48
|
|
|
42
49
|
generate:
|
|
43
50
|
generate dependence relationship for each file, this may accelarate
|
|
44
51
|
`canoe buid` command. It's recommanded to execute this command everytime
|
|
45
52
|
headers are added or removed from any file.
|
|
53
|
+
|
|
54
|
+
update:
|
|
55
|
+
this command is needed because '.canoe.deps' is actually a cache of dependency relationships so that canoe doesn't have to analyze all the files when building a project.
|
|
56
|
+
So when a file includes new headers or some headers are removed, users have to use 'canoe udpate'
|
|
57
|
+
to update dependency relationships.
|
|
46
58
|
|
|
47
59
|
build [options]:
|
|
48
60
|
build current project, arguments in [options] will be passed to C++ compiler
|
|
@@ -71,7 +83,7 @@ class WorkSpace
|
|
|
71
83
|
|
|
72
84
|
def initialize(name, mode, src_suffix='cpp', hdr_suffix='hpp')
|
|
73
85
|
@name = name
|
|
74
|
-
@compiler = Compiler.new 'clang++', '-Isrc/components'
|
|
86
|
+
@compiler = Compiler.new 'clang++', ['-Isrc/components']
|
|
75
87
|
@cwd = Dir.new(Dir.pwd)
|
|
76
88
|
@workspace = "#{Dir.pwd}/#{@name}"
|
|
77
89
|
@src = "#{@workspace}/src"
|
|
@@ -79,6 +91,7 @@ class WorkSpace
|
|
|
79
91
|
@obj = "#{@workspace}/obj"
|
|
80
92
|
@third = "#{@workspace}/third-party"
|
|
81
93
|
@target = "#{@workspace}/target"
|
|
94
|
+
@tests = "#{@workspace}/tests"
|
|
82
95
|
@mode = mode
|
|
83
96
|
@deps = '.canoe.deps'
|
|
84
97
|
|
|
@@ -91,18 +104,29 @@ class WorkSpace
|
|
|
91
104
|
end
|
|
92
105
|
|
|
93
106
|
def new
|
|
94
|
-
|
|
107
|
+
begin
|
|
108
|
+
Dir.mkdir(@name)
|
|
109
|
+
rescue
|
|
110
|
+
abort_on_err "workspace #{@name} already exsits"
|
|
111
|
+
end
|
|
95
112
|
Dir.mkdir(@src)
|
|
96
113
|
Dir.mkdir(@components)
|
|
97
114
|
Dir.mkdir("#{@workspace}/obj")
|
|
98
|
-
|
|
115
|
+
if @mode == :bin
|
|
116
|
+
DefaultFiles.create_main(@src, @source_suffix)
|
|
117
|
+
else
|
|
118
|
+
DefaultFiles.create_lib_header(@src, @name, @header_suffix)
|
|
119
|
+
end
|
|
99
120
|
File.new("#{@workspace}/.canoe", "w")
|
|
100
121
|
DefaultFiles.create_config @workspace, @source_suffix, @header_suffix
|
|
101
|
-
DefaultFiles.create_emacs_dir_local @workspace
|
|
122
|
+
# DefaultFiles.create_emacs_dir_local @workspace
|
|
102
123
|
|
|
103
124
|
Dir.mkdir(@third)
|
|
104
125
|
Dir.mkdir(@target)
|
|
105
|
-
|
|
126
|
+
Dir.chdir(@workspace) do
|
|
127
|
+
system "git init"
|
|
128
|
+
end
|
|
129
|
+
puts "workspace #{@workspace.blue} is created"
|
|
106
130
|
end
|
|
107
131
|
|
|
108
132
|
# args are commandline parameters passed to `canoe build`
|
|
@@ -114,7 +138,7 @@ class WorkSpace
|
|
|
114
138
|
build_time = File.exist?(target) ? File.mtime(target) : Time.new(0)
|
|
115
139
|
files = DepAnalyzer.compiling_filter(deps, build_time, @source_suffix, @header_suffix)
|
|
116
140
|
|
|
117
|
-
if files.empty?
|
|
141
|
+
if files.empty? && File.exist?(target)
|
|
118
142
|
puts "nothing to do, all up to date"
|
|
119
143
|
return
|
|
120
144
|
end
|
|
@@ -136,6 +160,7 @@ class WorkSpace
|
|
|
136
160
|
end
|
|
137
161
|
|
|
138
162
|
def run(args)
|
|
163
|
+
return if @mode == :lib
|
|
139
164
|
build []
|
|
140
165
|
args = args.join " "
|
|
141
166
|
puts "./target/#{@name} #{args}"
|
|
@@ -153,7 +178,7 @@ class WorkSpace
|
|
|
153
178
|
unless Dir.exist? dir
|
|
154
179
|
FileUtils.mkdir dir
|
|
155
180
|
Dir.chdir(dir) do
|
|
156
|
-
puts "created " + Dir.pwd
|
|
181
|
+
puts "created " + Dir.pwd.blue
|
|
157
182
|
create_working_files prefix.join('__'), filename
|
|
158
183
|
end
|
|
159
184
|
end
|
|
@@ -165,12 +190,23 @@ class WorkSpace
|
|
|
165
190
|
deps = DepAnalyzer.read_from(@deps) if File.exist?(@deps)
|
|
166
191
|
deps.each do |k, v|
|
|
167
192
|
unless v.empty?
|
|
168
|
-
puts "#{k} depends on: "
|
|
169
|
-
v.each {|f| puts " #{f}"}
|
|
193
|
+
puts "#{k.blue} depends on: "
|
|
194
|
+
v.each {|f| puts " #{f.blue}"}
|
|
170
195
|
puts ""
|
|
171
196
|
end
|
|
172
197
|
end
|
|
173
198
|
end
|
|
199
|
+
|
|
200
|
+
def test(args)
|
|
201
|
+
args.each do |arg|
|
|
202
|
+
case arg
|
|
203
|
+
when "all"
|
|
204
|
+
test_all
|
|
205
|
+
else
|
|
206
|
+
test_single arg
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
174
210
|
|
|
175
211
|
private
|
|
176
212
|
def create_working_files(prefix, filename)
|
|
@@ -208,40 +244,62 @@ class WorkSpace
|
|
|
208
244
|
@compiler.compile f, o
|
|
209
245
|
end
|
|
210
246
|
|
|
211
|
-
def
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
@compiler.
|
|
247
|
+
def link_exectutable(odir, objs)
|
|
248
|
+
puts "#{"[100%]".green} linking"
|
|
249
|
+
@compiler.link_executable "#{odir}/#{@name}", objs
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def link_shared(odir, objs)
|
|
253
|
+
puts "#{"[100%]".green} linking"
|
|
254
|
+
@compiler.link_shared "#{odir}/lib#{@name}", objs
|
|
219
255
|
end
|
|
220
256
|
|
|
221
257
|
def build_bin(files, args)
|
|
258
|
+
# return if files.empty?
|
|
222
259
|
build_compiler_from_config args
|
|
260
|
+
if build_common(files, args) && link_exectutable('./target', Dir.glob("obj/*.o"))
|
|
261
|
+
puts "BUILDING SUCCEEDED".green
|
|
262
|
+
else
|
|
263
|
+
puts "building FAILED".red
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def build_lib(files, args)
|
|
268
|
+
# return if files.empty?
|
|
269
|
+
build_compiler_from_config args
|
|
270
|
+
@compiler.append_compiling_flag '-fPIC'
|
|
271
|
+
if (build_common files, args) && link_shared('./target', Dir.glob("obj/*.o"))
|
|
272
|
+
puts "BUILDING SUCCEEDED".green
|
|
273
|
+
else
|
|
274
|
+
puts "building FAILED".red
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def build_common(files, args)
|
|
279
|
+
all = SourceFiles.get_all('./src') {|f| f.end_with? @source_suffix}
|
|
280
|
+
total = all.size.to_f
|
|
281
|
+
compiled = total - files.size
|
|
223
282
|
comps = files.select {|f| f.start_with? @components_prefix}
|
|
224
283
|
srcs = files - comps
|
|
225
|
-
|
|
284
|
+
flag = true;
|
|
226
285
|
srcs.each do |f|
|
|
227
|
-
|
|
286
|
+
progress = (compiled / total).round(2) * 100
|
|
287
|
+
printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
|
|
228
288
|
fname = f.split("/")[-1]
|
|
229
|
-
o = @obj_prefix +
|
|
230
|
-
compile f, o
|
|
289
|
+
o = @obj_prefix + File.basename(fname, ".*") + '.o'
|
|
290
|
+
flag = false unless compile f, o
|
|
291
|
+
compiled += 1
|
|
231
292
|
end
|
|
232
293
|
|
|
233
294
|
comps.each do |f|
|
|
234
|
-
|
|
295
|
+
progress = (compiled / total).round(2) * 100
|
|
296
|
+
printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
|
|
235
297
|
o = @obj_prefix + f.delete_suffix(File.extname(f))[@components_prefix.length..]
|
|
236
298
|
.gsub('/', '_') + '.o'
|
|
237
|
-
compile f, o
|
|
299
|
+
flag = false unless compile f, o
|
|
300
|
+
compiled += 1
|
|
238
301
|
end
|
|
239
|
-
|
|
240
|
-
link('./target', Dir.glob("obj/*.o")) unless files.empty?
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def build_lib
|
|
244
|
-
puts "build a lib"
|
|
302
|
+
flag
|
|
245
303
|
end
|
|
246
304
|
|
|
247
305
|
def clean_obj
|
metadata
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
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.1
|
|
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-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
|
-
description:
|
|
14
|
-
|
|
13
|
+
description: |+
|
|
14
|
+
Canoe offers project management and building facilities to C/C++ projects.
|
|
15
|
+
|
|
16
|
+
If you are tired of writing Makefile, CMakeList and even SConstruct, please let Canoe help you wipe them out.
|
|
17
|
+
|
|
15
18
|
Similar to Cargo for Rust, Canoe offers commands such as new, build, run, etc. to help you generate a C/C++ project and build it automatically.
|
|
16
|
-
|
|
19
|
+
|
|
20
|
+
Different from tools like Scons and Blade, Canoe requires users to write NO building scripts, Canoe would analyze dependencies and build like our old friend 'make' if a few conventions over file names are followed.
|
|
21
|
+
|
|
17
22
|
email: noahxiong@outlook.com
|
|
18
23
|
executables:
|
|
19
24
|
- canoe
|
|
@@ -23,6 +28,7 @@ files:
|
|
|
23
28
|
- bin/canoe
|
|
24
29
|
- lib/canoe.rb
|
|
25
30
|
- lib/cmd.rb
|
|
31
|
+
- lib/coloring.rb
|
|
26
32
|
- lib/compiler.rb
|
|
27
33
|
- lib/config_reader.rb
|
|
28
34
|
- lib/default_files.rb
|
|
@@ -42,7 +48,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
42
48
|
requirements:
|
|
43
49
|
- - ">="
|
|
44
50
|
- !ruby/object:Gem::Version
|
|
45
|
-
version:
|
|
51
|
+
version: 2.7.1
|
|
46
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
53
|
requirements:
|
|
48
54
|
- - ">="
|
|
@@ -52,5 +58,5 @@ requirements: []
|
|
|
52
58
|
rubygems_version: 3.1.2
|
|
53
59
|
signing_key:
|
|
54
60
|
specification_version: 4
|
|
55
|
-
summary: a C/C++ project management and
|
|
61
|
+
summary: a C/C++ project management and building tool
|
|
56
62
|
test_files: []
|