canoe 0.3.0.1 → 0.3.0.2

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: 7c1916c0ee5ce05d67222c84f93ac7e41de04895ffb523b1a5435276c6f8e11f
4
- data.tar.gz: f3b69717aed857c30f8154fb1f63126b8f84c42081890ef1be75c6d2a7250735
3
+ metadata.gz: acf64e52f86562fbb4103263adf6ac25d3583fdd8cc935df460d6df89ffa4367
4
+ data.tar.gz: 8f3e6ba476da88e1cd34abffb4bfa70e0ac910fb5bc93977601df49e44a75735
5
5
  SHA512:
6
- metadata.gz: adae82066e778ae3756d970b75fb87784087e25996051c9cd5dd5ad75f265c09418eeb5c4387db9b0c9c125d1b1739461f1f0a0dfc72cde9f1914a65023eb030
7
- data.tar.gz: 7d31ba373cf0a9a7f41178a153ee8fd7f9eb442a2698ec464c5ea9ca247b9816765f2bc17db1d0902209c6e6e4ff4bc238a4d7e9fa59cf74ba29a841bf519c3b
6
+ metadata.gz: e39ce423d813c64ef43c4440990439463a99dcb724771adc2d4d5db130c8206d7a3801c9fd036ee1477cd5c162f19b3da3dbc123e6114cba5bc7d8c0bf7d03a0
7
+ data.tar.gz: fe49d0b455bb21deb30b149f08736e2cff7091d8a3d38f87ac395fa1800c8b9abdb7c17594007412f5aacce448da5ebb60fd9a986fbf2ab645737aa59cd9100f
data/bin/canoe CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # require_relative '../lib/canoe'
2
3
  require 'canoe'
3
4
 
4
5
  Canoe.new.parse ARGV
@@ -1,4 +1,4 @@
1
- require_relative "workspace"
1
+ require_relative "workspace/workspace.rb"
2
2
  require_relative "cmd"
3
3
  require_relative "source_files"
4
4
 
@@ -13,7 +13,8 @@ class Canoe
13
13
  'clean',
14
14
  'version',
15
15
  'help',
16
- 'update']
16
+ 'update',
17
+ 'test']
17
18
  @cmd = CmdParser.new options
18
19
  end
19
20
 
data/lib/cmd.rb CHANGED
@@ -1,4 +1,4 @@
1
- require_relative "workspace"
1
+ require_relative "workspace/workspace"
2
2
  require_relative "err"
3
3
  require_relative "config_reader"
4
4
 
@@ -94,7 +94,7 @@ class CmdParser
94
94
 
95
95
  def parse_version(args)
96
96
  puts <<~VER
97
- canoe v0.3.0
97
+ canoe v0.3.0.2
98
98
  For features in this version, please visit https://github.com/Dicridon/canoe
99
99
  Currently, canoe can do below:
100
100
  - project creation
@@ -6,10 +6,10 @@ class Compiler
6
6
  ##
7
7
  # @name: String
8
8
  # @flgs: Array of String
9
- def initialize(name, flgs)
9
+ def initialize(name, compiling_flags, linking_flags)
10
10
  @name = name
11
- @linking_flags = flgs.filter {|f| f.start_with? "-l"}
12
- @compiling_flags = flgs - @linking_flags
11
+ @linking_flags = linking_flags
12
+ @compiling_flags = compiling_flags
13
13
  end
14
14
 
15
15
  def compiling_flags_as_str
@@ -19,9 +19,14 @@ class DefaultFiles
19
19
  "header-suffix": "#{hdr_sfx}",
20
20
  "source-suffix": "#{src_sfx}",
21
21
  "flags": {
22
- "opt": "-O2",
23
- "debug": "-g",
24
- "std": "-std=c++17"
22
+ "compile": {
23
+ "opt": "-O2",
24
+ "debug": "-g",
25
+ "std": "-std=c++17"
26
+ },
27
+ "link": {
28
+
29
+ }
25
30
  }
26
31
  }
27
32
  CONFIG
@@ -47,6 +47,8 @@ class DepAnalyzer
47
47
  v.each do |f|
48
48
  if mark(f, build_time, deps) || mark(f.sub(".#{hdr_sfx}", ".#{src_sfx}"), build_time, deps)
49
49
  files << k
50
+ @processed[k] = true
51
+ @recompiles[k] = true
50
52
  break
51
53
  end
52
54
  end
@@ -56,12 +58,16 @@ class DepAnalyzer
56
58
 
57
59
  private
58
60
  def self.mark(file, build_time, deps)
61
+ ret = false
59
62
  return false unless File.exists? file
60
63
  if should_recompile?(file, build_time)
61
64
  return true
62
65
  else
63
66
  deps[file].each do |f|
64
- return @recompiles[f] if @processed[f]
67
+ if @processed[f]
68
+ ret |= @recompiles[f]
69
+ next
70
+ end
65
71
  @processed[f] = true
66
72
  if mark(f, build_time, deps)
67
73
  @recompiles[f] = true
@@ -69,7 +75,7 @@ class DepAnalyzer
69
75
  end
70
76
  end
71
77
  end
72
- false
78
+ ret
73
79
  end
74
80
 
75
81
  def self.should_recompile?(file, build_time)
@@ -0,0 +1,26 @@
1
+ class WorkSpace
2
+ def add(args)
3
+ args.each do |i|
4
+ dir = @components
5
+ filenames = i.split("/")
6
+ prefix = []
7
+ filenames.each do |filename|
8
+ dir += "/#{filename}"
9
+ prefix << filename
10
+ unless Dir.exist? dir
11
+ FileUtils.mkdir dir
12
+ Dir.chdir(dir) do
13
+ puts "created " + Dir.pwd.blue
14
+ create_working_files prefix.join('__'), filename
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+ def create_working_files(prefix, filename)
23
+ DefaultFiles.create_cpp filename, @source_suffix, @header_suffix
24
+ DefaultFiles.create_hpp @name, prefix, filename, @header_suffix
25
+ end
26
+ end
@@ -0,0 +1,130 @@
1
+ class WorkSpace
2
+ # args are commandline parameters passed to `canoe build`,
3
+ # could be 'all', 'test', 'target' or empty
4
+ def build(args)
5
+ case args[0]
6
+ when "all"
7
+ build_all
8
+ when "test"
9
+ build_test
10
+ else
11
+ build_target
12
+ end
13
+ end
14
+
15
+ private
16
+ def build_flags(flags, config)
17
+ config.values.each do |v|
18
+ case v
19
+ when String
20
+ flags << v
21
+ when Array
22
+ v.each do |o|
23
+ flags << o
24
+ end
25
+ else
26
+ abort_on_err "unknown options in config.json, #{v}"
27
+ end
28
+ end
29
+ end
30
+
31
+ def build_compiler_from_config
32
+ Dir.chdir(@workspace) do
33
+ flags = ConfigReader.extract_flags "config.json"
34
+ compiler_name = flags['compiler'] ? flags['compiler'] : "clang++"
35
+ abort_on_err "compiler #{compiler_name} not found" unless File.exists?("/usr/bin/#{compiler_name}")
36
+ compiler_flags = ['-Isrc/components']
37
+ linker_flags = []
38
+
39
+ c_flags, l_flags = flags['flags']['compile'], flags['flags']['link']
40
+ build_flags(compiler_flags, c_flags)
41
+ build_flags(linker_flags, l_flags)
42
+
43
+ @compiler = Compiler.new compiler_name, compiler_flags, linker_flags
44
+ end
45
+ end
46
+
47
+ def compile(f, o)
48
+ @compiler.compile f, o
49
+ end
50
+
51
+ def link_exectutable(odir, objs)
52
+ puts "#{"[100%]".green} linking"
53
+ @compiler.link_executable "#{odir}/#{@name}", objs
54
+ end
55
+
56
+ def link_shared(odir, objs)
57
+ puts "#{"[100%]".green} linking"
58
+ @compiler.link_shared "#{odir}/lib#{@name}", objs
59
+ end
60
+
61
+ def build_bin(files)
62
+ # return if files.empty?
63
+ build_compiler_from_config
64
+ if build_common(files) && link_exectutable('./target', Dir.glob("obj/*.o"))
65
+ puts "BUILDING SUCCEEDED".green
66
+ else
67
+ puts "building FAILED".red
68
+ end
69
+ end
70
+
71
+ def build_lib(files)
72
+ # return if files.empty?
73
+ build_compiler_from_config
74
+ @compiler.append_compiling_flag '-fPIC'
75
+ if build_common(files) && link_shared('./target', Dir.glob("obj/*.o"))
76
+ puts "BUILDING SUCCEEDED".green
77
+ else
78
+ puts "building FAILED".red
79
+ end
80
+ end
81
+
82
+ def build_common(files)
83
+ all = SourceFiles.get_all('./src') {|f| f.end_with? @source_suffix}
84
+ total = all.size.to_f
85
+ compiled = total - files.size
86
+ comps = files.select {|f| f.start_with? @components_prefix}
87
+ srcs = files - comps
88
+ flag = true;
89
+
90
+ srcs.each do |f|
91
+ progress = (compiled / total).round(2) * 100
92
+ printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
93
+ fname = f.split("/")[-1]
94
+ o = @obj_prefix + File.basename(fname, ".*") + '.o'
95
+ flag = false unless compile f, o
96
+ compiled += 1
97
+ end
98
+
99
+ comps.each do |f|
100
+ progress = (compiled / total).round(2) * 100
101
+ printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
102
+ o = @obj_prefix + f.delete_suffix(File.extname(f))[@components_prefix.length..]
103
+ .gsub('/', '_') + '.o'
104
+ flag = false unless compile f, o
105
+ compiled += 1
106
+ end
107
+ flag
108
+ end
109
+
110
+ def build_all
111
+ build_target
112
+ build_test
113
+ end
114
+
115
+ def build_target
116
+ deps = File.exist?(@deps) ?
117
+ DepAnalyzer.read_from(@deps) :
118
+ DepAnalyzer.new('./src').build_to_file(['./src', './src/components'], @deps)
119
+ target = "./target/#{@name}"
120
+ build_time = File.exist?(target) ? File.mtime(target) : Time.new(0)
121
+ files = DepAnalyzer.compiling_filter(deps, build_time, @source_suffix, @header_suffix)
122
+
123
+ if files.empty? && File.exist?(target)
124
+ puts "nothing to do, all up to date"
125
+ return
126
+ end
127
+
128
+ self.send "build_#{@mode.to_s}", files
129
+ end
130
+ end
@@ -0,0 +1,26 @@
1
+ class WorkSpace
2
+ def clean
3
+ self.send "clean_#{@mode.to_s}"
4
+ end
5
+
6
+ private
7
+ def clean_obj
8
+ puts "rm -f ./obj/*.o"
9
+ system "rm -f ./obj/*.o"
10
+ end
11
+
12
+ def clean_target
13
+ puts "rm -f ./target/*"
14
+ system "rm -f ./target/*"
15
+ end
16
+
17
+ def clean_bin
18
+ clean_obj
19
+ clean_target
20
+ end
21
+
22
+ def clean_lib
23
+ clean_obj
24
+ clean_target
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ class WorkSpace
2
+ def dep
3
+ deps = DepAnalyzer.read_from(@deps) if File.exist?(@deps)
4
+ deps.each do |k, v|
5
+ unless v.empty?
6
+ puts "#{k.blue} depends on: "
7
+ v.each {|f| puts " #{f.blue}"}
8
+ puts ""
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ class WorkSpace
2
+ def generate
3
+ DepAnalyzer.new('./src', @source_suffix, @header_suffix)
4
+ .build_to_file ['./src', './src/components'], @deps
5
+ end
6
+ end
@@ -0,0 +1,71 @@
1
+ class WorkSpace
2
+ def self.help
3
+ info = <<~INFO
4
+ canoe is a C/C++ project manager, inspired by Rust cargo.
5
+ usage:
6
+ canoe new tada: create a project named 'tada' in current directory
7
+
8
+ canoe build: compile current project (execute this command in project directory)
9
+
10
+ canoe generate: generate dependency relationships and store it in '.canoe.deps' file. Alias: update
11
+
12
+ canoe update: udpate dependency relationships and store it in '.canoe.deps' file.
13
+
14
+ canoe run: compile and execute current project (execute this command in project directory)
15
+
16
+ canoe clean: remove all generated object files and binary files
17
+
18
+ canoe help: show this help message
19
+
20
+ canoe add tada: add a folder named tada under workspace/components,
21
+
22
+ canoe dep: show current dependency relationships of current project
23
+
24
+ canoe verion: version information
25
+
26
+ new project_name [mode] [suffixes]:
27
+ create a new project with project_name.
28
+ In this project, four directories obj, src, target and third-party will be generated in project directory.
29
+ in src, directory 'components' will be generated if [mode] is '--lib', an extra main.cpp will be generated if [mode] is '--bin'
30
+
31
+ [mode]: --lib for a library and --bin for executable binaries
32
+ [suffixes]: should be in 'source_suffix:header_suffix" format, notice the ':' between two suffixes
33
+ add component_name:
34
+ add a folder named tada under workspace/components.
35
+ two files tada.hpp and tada.cpp would be craeted and intialized. File suffix may differ according users' specifications.
36
+ if component_name is a path separated by '/', then canoe would create folders and corresponding files recursively.
37
+
38
+ generate:
39
+ generate dependence relationship for each file, this may accelarate
40
+ `canoe buid` command. It's recommanded to execute this command everytime
41
+ headers are added or removed from any file.
42
+
43
+ update:
44
+ 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.
45
+ So when a file includes new headers or some headers are removed, users have to use 'canoe udpate'
46
+ to update dependency relationships.
47
+
48
+ build [options]:
49
+ build current project, arguments in [options] will be passed to C++ compiler
50
+
51
+ run [options]:
52
+ build current project with no specific compilation flags, and run this project, passing [options] as command line arguments to the binary
53
+
54
+ clean:
55
+ remove all generated object files and binary files
56
+
57
+ help:
58
+ show this help message
59
+
60
+ verion:
61
+ display version information
62
+
63
+ dep:
64
+ display file dependencies in a better readable way
65
+
66
+ @author: written by XIONG Ziwei, ICT, CAS
67
+ @contact: noahxiong@outlook.com
68
+ INFO
69
+ puts info
70
+ end
71
+ end
@@ -0,0 +1,28 @@
1
+ class WorkSpace
2
+ def new
3
+ begin
4
+ Dir.mkdir(@name)
5
+ rescue
6
+ abort_on_err "workspace #{@name} already exsits"
7
+ end
8
+ Dir.mkdir(@src)
9
+ Dir.mkdir(@components)
10
+ Dir.mkdir("#{@workspace}/obj")
11
+ if @mode == :bin
12
+ DefaultFiles.create_main(@src, @source_suffix)
13
+ else
14
+ DefaultFiles.create_lib_header(@src, @name, @header_suffix)
15
+ end
16
+ File.new("#{@workspace}/.canoe", "w")
17
+ DefaultFiles.create_config @workspace, @source_suffix, @header_suffix
18
+ # DefaultFiles.create_emacs_dir_local @workspace
19
+
20
+ Dir.mkdir(@third)
21
+ Dir.mkdir(@target)
22
+ Dir.mkdir(@tests)
23
+ Dir.chdir(@workspace) do
24
+ system "git init"
25
+ end
26
+ puts "workspace #{@workspace.blue} is created"
27
+ end
28
+ end
@@ -0,0 +1,9 @@
1
+ class WorkSpace
2
+ def run(args)
3
+ return if @mode == :lib
4
+ build []
5
+ args = args.join " "
6
+ puts "./target/#{@name} #{args}"
7
+ exec "./target/#{@name} #{args}"
8
+ end
9
+ end
@@ -0,0 +1,39 @@
1
+ class WorkSpace
2
+ public
3
+ def test(args)
4
+ if args.empty?
5
+ test_all
6
+ return
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
17
+ end
18
+
19
+ private
20
+ def test_all
21
+ puts "tests all"
22
+ end
23
+
24
+ def test_single(name)
25
+ puts "#{@tests}/bin/test_#{name}"
26
+ # system "./#{@tests}/bin/test_#{name}"
27
+ end
28
+
29
+ ##
30
+ # how to build:
31
+ # each test file tests one or more components, indicated by included headers
32
+ # find corresponding object file in ../obj and link them to test file
33
+ # TODO
34
+ def build_test
35
+ build
36
+ deps = DepAnalyzer.new('./tests').build_to_file(['./src', './src/components', './tests', './tests/common'], './tests/.canoe.deps')
37
+ puts deps
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ class WorkSpace
2
+ def update
3
+ generate
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ class WorkSpace
2
+ def version
3
+ puts <<~VER
4
+ canoe v0.3.0.2
5
+ For features in this version, please visit https://github.com/Dicridon/canoe
6
+ Currently, canoe can do below:
7
+ - project creation
8
+ - project auto build and run (works like Cargo for Rust)
9
+ - project structure management
10
+ by XIONG Ziwei
11
+ VER
12
+ end
13
+ end
@@ -0,0 +1,53 @@
1
+ require 'fileutils'
2
+ require_relative '../source_files'
3
+ require_relative '../compiler'
4
+ require_relative '../config_reader'
5
+ require_relative '../default_files'
6
+ require_relative '../err'
7
+ require_relative '../dependence'
8
+ require_relative '../coloring'
9
+
10
+
11
+ class WorkSpace
12
+ include Err
13
+ attr_reader :name, :cwd
14
+
15
+ def initialize(name, mode, src_suffix='cpp', hdr_suffix='hpp')
16
+ @name = name
17
+ @compiler = Compiler.new 'clang++', ['-Isrc/components'], []
18
+ @cwd = Dir.new(Dir.pwd)
19
+ @workspace = "#{Dir.pwd}/#{@name}"
20
+ @src = "#{@workspace}/src"
21
+ @components = "#{@src}/components"
22
+ @obj = "#{@workspace}/obj"
23
+ @third = "#{@workspace}/third-party"
24
+ @target = "#{@workspace}/target"
25
+ @tests = "#{@workspace}/tests"
26
+ @mode = mode
27
+ @deps = '.canoe.deps'
28
+
29
+ @src_prefix = './src/'
30
+ @components_prefix = './src/components/'
31
+ @obj_prefix = './obj/'
32
+
33
+ @source_suffix = src_suffix
34
+ @header_suffix = hdr_suffix
35
+ end
36
+
37
+ def inspect
38
+ puts "name is #{@name}"
39
+ puts "name is #{@workspace}"
40
+ end
41
+ end
42
+
43
+ require_relative 'help'
44
+ require_relative 'new'
45
+ require_relative 'add'
46
+ require_relative 'build'
47
+ require_relative 'generate'
48
+ require_relative 'run'
49
+ require_relative 'dep'
50
+ require_relative 'clean'
51
+ require_relative 'version'
52
+ require_relative 'update'
53
+ require_relative 'test'
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.0.1
4
+ version: 0.3.0.2
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-07-11 00:00:00.000000000 Z
11
+ date: 2020-09-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |+
14
14
  Canoe offers project management and building facilities to C/C++ projects.
@@ -35,7 +35,18 @@ files:
35
35
  - lib/dependence.rb
36
36
  - lib/err.rb
37
37
  - lib/source_files.rb
38
- - lib/workspace.rb
38
+ - lib/workspace/add.rb
39
+ - lib/workspace/build.rb
40
+ - lib/workspace/clean.rb
41
+ - lib/workspace/dep.rb
42
+ - lib/workspace/generate.rb
43
+ - lib/workspace/help.rb
44
+ - lib/workspace/new.rb
45
+ - lib/workspace/run.rb
46
+ - lib/workspace/test.rb
47
+ - lib/workspace/update.rb
48
+ - lib/workspace/version.rb
49
+ - lib/workspace/workspace.rb
39
50
  homepage: https://github.com/Dicridon/canoe
40
51
  licenses:
41
52
  - MIT
@@ -1,330 +0,0 @@
1
- require 'fileutils'
2
- require_relative 'source_files'
3
- require_relative 'compiler'
4
- require_relative 'config_reader'
5
- require_relative 'default_files'
6
- require_relative 'err'
7
- require_relative 'dependence'
8
- require_relative 'coloring'
9
-
10
- class WorkSpace
11
- include Err
12
- attr_reader :name, :cwd
13
- def self.help
14
- info = <<~INFO
15
- canoe is a C/C++ project manager, inspired by Rust cargo.
16
- usage:
17
- canoe new tada: create a project named 'tada' in current directory
18
-
19
- canoe build: compile current project (execute this command in project directory)
20
-
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.
24
-
25
- canoe run: compile and execute current project (execute this command in project directory)
26
-
27
- canoe clean: remove all generated object files and binary files
28
-
29
- canoe help: show this help message
30
-
31
- canoe add tada: add a folder named tada under workspace/components,
32
-
33
- canoe dep: show current dependency relationships of current project
34
-
35
- canoe verion: version information
36
-
37
- new project_name [mode] [suffixes]:
38
- create a new project with project_name.
39
- In this project, four directories obj, src, target and third-party will be generated in project directory.
40
- in src, directory 'components' will be generated if [mode] is '--lib', an extra main.cpp will be generated if [mode] is '--bin'
41
-
42
- [mode]: --lib for a library and --bin for executable binaries
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.
48
-
49
- generate:
50
- generate dependence relationship for each file, this may accelarate
51
- `canoe buid` command. It's recommanded to execute this command everytime
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.
58
-
59
- build [options]:
60
- build current project, arguments in [options] will be passed to C++ compiler
61
-
62
- run [options]:
63
- build current project with no specific compilation flags, and run this project, passing [options] as command line arguments to the binary
64
-
65
- clean:
66
- remove all generated object files and binary files
67
-
68
- help:
69
- show this help message
70
-
71
- verion:
72
- display version information
73
-
74
- dep:
75
- display file dependencies in a better readable way
76
-
77
- @author: written by XIONG Ziwei, ICT, CAS
78
- @contact: noahxiong@outlook.com
79
- INFO
80
- puts info
81
- end
82
-
83
-
84
- def initialize(name, mode, src_suffix='cpp', hdr_suffix='hpp')
85
- @name = name
86
- @compiler = Compiler.new 'clang++', ['-Isrc/components']
87
- @cwd = Dir.new(Dir.pwd)
88
- @workspace = "#{Dir.pwd}/#{@name}"
89
- @src = "#{@workspace}/src"
90
- @components = "#{@src}/components"
91
- @obj = "#{@workspace}/obj"
92
- @third = "#{@workspace}/third-party"
93
- @target = "#{@workspace}/target"
94
- @tests = "#{@workspace}/tests"
95
- @mode = mode
96
- @deps = '.canoe.deps'
97
-
98
- @src_prefix = './src/'
99
- @components_prefix = './src/components/'
100
- @obj_prefix = './obj/'
101
-
102
- @source_suffix = src_suffix
103
- @header_suffix = hdr_suffix
104
- end
105
-
106
- def new
107
- begin
108
- Dir.mkdir(@name)
109
- rescue
110
- abort_on_err "workspace #{@name} already exsits"
111
- end
112
- Dir.mkdir(@src)
113
- Dir.mkdir(@components)
114
- Dir.mkdir("#{@workspace}/obj")
115
- if @mode == :bin
116
- DefaultFiles.create_main(@src, @source_suffix)
117
- else
118
- DefaultFiles.create_lib_header(@src, @name, @header_suffix)
119
- end
120
- File.new("#{@workspace}/.canoe", "w")
121
- DefaultFiles.create_config @workspace, @source_suffix, @header_suffix
122
- # DefaultFiles.create_emacs_dir_local @workspace
123
-
124
- Dir.mkdir(@third)
125
- Dir.mkdir(@target)
126
- Dir.chdir(@workspace) do
127
- system "git init"
128
- end
129
- puts "workspace #{@workspace.blue} is created"
130
- end
131
-
132
- # args are commandline parameters passed to `canoe build`
133
- def build(args)
134
- deps = File.exist?(@deps) ?
135
- DepAnalyzer.read_from(@deps) :
136
- DepAnalyzer.new('./src').build_to_file(['./src', './src/components'], @deps)
137
- target = "./target/#{@name}"
138
- build_time = File.exist?(target) ? File.mtime(target) : Time.new(0)
139
- files = DepAnalyzer.compiling_filter(deps, build_time, @source_suffix, @header_suffix)
140
-
141
- if files.empty? && File.exist?(target)
142
- puts "nothing to do, all up to date"
143
- return
144
- end
145
-
146
- self.send "build_#{@mode.to_s}", files, args
147
- end
148
-
149
- def generate
150
- DepAnalyzer.new('./src', @source_suffix, @header_suffix)
151
- .build_to_file ['./src', './src/components'], @deps
152
- end
153
-
154
- def update
155
- generate
156
- end
157
-
158
- def clean
159
- self.send "clean_#{@mode.to_s}"
160
- end
161
-
162
- def run(args)
163
- return if @mode == :lib
164
- build []
165
- args = args.join " "
166
- puts "./target/#{@name} #{args}"
167
- exec "./target/#{@name} #{args}"
168
- end
169
-
170
- def add(args)
171
- args.each do |i|
172
- dir = @components
173
- filenames = i.split("/")
174
- prefix = []
175
- filenames.each do |filename|
176
- dir += "/#{filename}"
177
- prefix << filename
178
- unless Dir.exist? dir
179
- FileUtils.mkdir dir
180
- Dir.chdir(dir) do
181
- puts "created " + Dir.pwd.blue
182
- create_working_files prefix.join('__'), filename
183
- end
184
- end
185
- end
186
- end
187
- end
188
-
189
- def dep
190
- deps = DepAnalyzer.read_from(@deps) if File.exist?(@deps)
191
- deps.each do |k, v|
192
- unless v.empty?
193
- puts "#{k.blue} depends on: "
194
- v.each {|f| puts " #{f.blue}"}
195
- puts ""
196
- end
197
- end
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
210
-
211
- private
212
- def create_working_files(prefix, filename)
213
- DefaultFiles.create_cpp filename, @source_suffix, @header_suffix
214
- DefaultFiles.create_hpp @name, prefix, filename, @header_suffix
215
- end
216
-
217
- def build_compiler_from_config(args)
218
- Dir.chdir(@workspace) do
219
- flags = ConfigReader.extract_flags "config.json"
220
- compiler_name = flags['compiler'] ? flags['compiler'] : "clang++"
221
- abort_on_err "compiler #{compiler_name} not found" unless File.exists?("/usr/bin/#{compiler_name}")
222
- compiler_flags = ['-Isrc/components'] + args
223
-
224
- if opts = flags['flags']
225
- opts.each do |k, v|
226
- case v
227
- when String
228
- compiler_flags << v
229
- when Array
230
- v.each do |o|
231
- compiler_flags << o
232
- end
233
- else
234
- abort_on_err "unknown options in config.json, #{v}"
235
- end
236
- end
237
- end
238
-
239
- @compiler = Compiler.new compiler_name, compiler_flags
240
- end
241
- end
242
-
243
- def compile(f, o)
244
- @compiler.compile f, o
245
- end
246
-
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
255
- end
256
-
257
- def build_bin(files, args)
258
- # return if files.empty?
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
282
- comps = files.select {|f| f.start_with? @components_prefix}
283
- srcs = files - comps
284
- flag = true;
285
- srcs.each do |f|
286
- progress = (compiled / total).round(2) * 100
287
- printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
288
- fname = f.split("/")[-1]
289
- o = @obj_prefix + File.basename(fname, ".*") + '.o'
290
- flag = false unless compile f, o
291
- compiled += 1
292
- end
293
-
294
- comps.each do |f|
295
- progress = (compiled / total).round(2) * 100
296
- printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
297
- o = @obj_prefix + f.delete_suffix(File.extname(f))[@components_prefix.length..]
298
- .gsub('/', '_') + '.o'
299
- flag = false unless compile f, o
300
- compiled += 1
301
- end
302
- flag
303
- end
304
-
305
- def clean_obj
306
- puts "rm -f ./obj/*.o"
307
- system "rm -f ./obj/*.o"
308
- end
309
-
310
- def clean_target
311
- puts "rm -f ./target/*"
312
- system "rm -f ./target/*"
313
- end
314
-
315
- def clean_bin
316
- clean_obj
317
- clean_target
318
- end
319
-
320
- def clean_lib
321
- clean_obj
322
- clean_target
323
- end
324
-
325
- public
326
- def inspect
327
- puts "name is #{@name}"
328
- puts "name is #{@workspace}"
329
- end
330
- end