/
main.cr
136 lines (123 loc) · 3.41 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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
exit(status, ex)
end
# :nodoc:
def self.exit(status : Int32, exception : Exception?) : Int32
status = Crystal::AtExitHandlers.run status, exception
if exception
STDERR.print "Unhandled exception: "
exception.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.
#
# On Windows the actual entry point is `wmain`, but there is no need to redefine
# that. See the file required below for details.
fun main(argc : Int32, argv : UInt8**) : Int32
Crystal.main(argc, argv)
end
{% if flag?(:win32) %}
require "./system/win32/wmain"
{% end %}
{% if flag?(:wasi) %}
require "./system/wasi/main"
{% end %}