/
main.cr
120 lines (110 loc) · 3.03 KB
/
main.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
lib LibCrystalMain
@[Raises]
fun __crystal_main(argc : Int32, argv : UInt8**)
end
module Crystal
# Defines the main routine run by normal Crystal programs:
#
# - Initializes the GC
# - Invokes the given *block*
# - Handles unhandled exceptions
# - Invokes `at_exit` handlers
# - Flushes `STDOUT` and `STDERR`
#
# This method can be invoked if you need to define a custom
# main (as in C main) function, doing all the above steps.
#
# For example:
#
# ```
# fun main(argc : Int32, argv : UInt8**) : Int32
# Crystal.main do
# elapsed = Time.measure do
# Crystal.main_user_code(argc, argv)
# end
# puts "Time to execute program: #{elapsed}"
# end
# end
# ```
#
# Note that the above is really just an example, almost the
# same can be accomplished with `at_exit`. But in some cases
# redefinition of C's main is needed.
def self.main(&block)
GC.init
status =
begin
yield
0
rescue ex
1
end
status = Crystal::AtExitHandlers.run status, ex
if ex
STDERR.print "Unhandled exception: "
ex.inspect_with_backtrace(STDERR)
end
ignore_stdio_errors { STDOUT.flush }
ignore_stdio_errors { STDERR.flush }
status
end
# :nodoc:
def self.ignore_stdio_errors
yield
rescue IO::Error
end
# Main method run by all Crystal programs at startup.
#
# This setups up the GC, invokes your program, rescuing
# any handled exception, and then runs `at_exit` handlers.
#
# This method is automatically invoked for you, so you
# don't need to invoke it.
#
# However, if you need to define a special main C function,
# you can redefine main and invoke `Crystal.main` from it:
#
# ```
# fun main(argc : Int32, argv : UInt8**) : Int32
# # some setup before Crystal main
# Crystal.main(argc, argv)
# # some cleanup logic after Crystal main
# end
# ```
#
# The `Crystal.main` can also be passed as a callback:
#
# ```
# fun main(argc : Int32, argv : UInt8**) : Int32
# LibFoo.init_foo_and_invoke_main(argc, argv, ->Crystal.main(Int32, UInt8**))
# end
# ```
#
# Note that before `Crystal.main` is invoked the GC
# is not setup yet, so nothing that allocates memory
# in Crystal (like `new` for classes) can be used.
def self.main(argc : Int32, argv : UInt8**)
main do
main_user_code(argc, argv)
end
rescue ex
Crystal::System.print_exception "Unhandled exception", ex
1
end
# Executes the main user code. This normally is executed
# after initializing the GC and before executing `at_exit` handlers.
#
# You should never invoke this method unless you need to
# redefine C's main function. See `Crystal.main` for
# more details.
def self.main_user_code(argc : Int32, argv : UInt8**)
LibCrystalMain.__crystal_main(argc, argv)
end
end
# Main function that acts as C's main function.
# Invokes `Crystal.main`.
#
# Can be redefined. See `Crystal.main` for examples.
fun main(argc : Int32, argv : UInt8**) : Int32
Crystal.main(argc, argv)
end