Description:
merge
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r230:791a8b27f2e4 - - 3 files changed: 16 inserted, 5 deleted

@@ -1,88 +1,90
1 1 #!/usr/bin/env ruby
2 2
3 3 require 'fileutils'
4 4
5 5 ##############################
6 6 #
7 7 # Standard Compile Script
8 8 #
9 9 # Supported compilers:
10 10 # gcc, g++, and fpc.
11 11 #
12 12 ##############################
13 13
14 14 def talk(str='')
15 15 if ENV['TALKATIVE']!=nil
16 16 puts str
17 17 end
18 18 if ENV['GRADER_LOGGING']!=nil
19 19 log_fname = ENV['GRADER_LOGGING']
20 20 fp = File.open(log_fname,"a")
21 21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
22 22 fp.close
23 23 end
24 24 end
25 25
26 26 C_COMPILER = "/usr/bin/gcc"
27 27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
28 28 PASCAL_COMPILER = "/usr/bin/fpc"
29 29 JAVA_COMPILER = "/usr/bin/javac"
30 30 RUBY_INTERPRETER = "/usr/bin/ruby"
31 31 PYTHON_INTERPRETER = "/usr/bin/python3"
32 32 PYTHON_CHECKER = "/usr/bin/pyflakes"
33 33 PHP_INTERPRETER = "/usr/bin/php"
34 + HASKELL_COMPILER = "/usr/bin/ghc"
34 35
35 36 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
36 37 CPLUSPLUS_OPTIONS = "-O2 -s -std=c++11 -static -DCONTEST -lm -Wall"
37 38 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
38 39 JAVA_OPTIONS = ""
39 40 PYTHON_OPTIONS = ""
40 41 PHP_OPTIONS = "-l"
42 + HASKELL_OPTIONS = ""
41 43
42 44 # Check for the correct number of arguments. Otherwise, print usage.
43 45 if ARGV.length == 0 or ARGV.length > 4
44 46 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
45 47 puts
46 48 puts "<source-file> is defaulted to \"source\"."
47 49 puts "<output-file> is defaulted to \"a.out\"."
48 50 puts "<message-file> is defaulted to \"compiler_message\"."
49 51 puts
50 52 exit(127)
51 53 end
52 54
53 55 PARAMS = {
54 56 :source_file => [1,'source'],
55 57 :output_file => [2,'a.out'],
56 58 :message_file => [3,'compiler_message']
57 59 }
58 60
59 61 params = {}
60 62 params[:prog_lang] = ARGV[0]
61 63 PARAMS.each_key do |param_name|
62 64 index, default = PARAMS[param_name]
63 65 if ARGV.length > index
64 66 params[param_name] = ARGV[index]
65 67 else
66 68 params[param_name] = default
67 69 end
68 70 talk "#{param_name}: #{params[param_name]}"
69 71 end
70 72
71 73 # Remove any remaining output files or message files.
72 74 if FileTest.exists? params[:output_file]
73 75 FileUtils.rm(params[:output_file])
74 76 end
75 77 if FileTest.exists? params[:message_file]
76 78 FileUtils.rm(params[:message_file])
77 79 end
78 80
79 81 # Check if the source file exists before attempt compiling.
80 82 if !FileTest.exists? params[:source_file]
81 83 talk("ERROR: The source file does not exist!")
82 84 open(params[:message_file],"w") do |f|
83 85 f.puts "ERROR: The source file did not exist."
84 86 end
85 87 exit(127)
86 88 end
87 89
88 90 if params[:prog_lang]=='cpp'
@@ -100,89 +102,95
100 102 command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS}"
101 103 system(command, err: params[:message_file])
102 104
103 105 when "pas"
104 106 command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS}"
105 107 system(command,out: params[:message_file])
106 108 FileUtils.mv("output", params[:output_file])
107 109
108 110 when "java"
109 111 #rename the file to the public class name
110 112
111 113 #get the class name
112 114 classname = 'DUMMY'
113 115 source = Array.new
114 116 File.foreach(params[:source_file],'r:UTF-8') do |line|
115 117 line.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
116 118 md = /\s*public\s*class\s*(\w*)/.match(line)
117 119 classname=md[1] if md
118 120 source << line unless line =~ /\s*package\s*\w+\s*\;/
119 121 end
120 122 File.open("#{classname}.java","w") do |file|
121 123 source.each do |s|
122 124 file.puts s
123 125 end
124 126 end
125 127 #system("cp #{params[:source_file]} #{classname}.java")
126 128 command = "#{JAVA_COMPILER} -encoding utf8 #{classname}.java"
127 129 system(command, err: params[:message_file])
128 130 if File.exists?(classname + ".class")
129 131 File.open(params[:output_file],"w") {|file| file.write("#{classname}")}
130 132 end
131 133 if classname == 'DUMMY'
132 134 File.open(params[:message_file],"w") {|file| file.write("Cannot find any public class in the source code\n")}
133 135 end
134 136
135 137 when "ruby"
136 138 command = "#{RUBY_INTERPRETER} -c #{params[:source_file]}"
137 139 if system(command, err: params[:message_file])
138 140 File.open(params[:output_file],"w") do |out_file|
139 141 out_file.puts "#!#{RUBY_INTERPRETER}"
140 142 File.open(params[:source_file],"r").each do |line|
141 143 out_file.print line
142 144 end
143 145 end
144 146 File.chmod(0755, params[:output_file])
145 147 end
146 148
147 149 when "python"
148 - command = "#{PYTHON_CHECKER} #{params[:source_file]}"
149 - if system(command, out: params[:message_file])
150 + #command = "#{PYTHON_CHECKER} #{params[:source_file]}"
151 + #if system(command, out: params[:message_file])
150 152 #compile to python bytecode
151 153 command = "#{PYTHON_INTERPRETER} -c \"import py_compile; py_compile.compile('#{params[:source_file]}','#{params[:source_file]}c');\""
152 154 puts "compile: #{command}"
153 - system(command)
155 + system(command, err: params[:message_file])
156 + if FileTest.exists?("#{params[:source_file]}c")
154 157 puts "pwd: " + Dir.pwd
155 158 Dir.new('.').each {|file| puts file}
156 159 File.open(params[:output_file],"w") do |out_file|
157 160 out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
158 161 end
159 162 File.chmod(0755, params[:output_file])
160 163 FileUtils.cp("#{params[:source_file]}c",params[:output_file])
161 164 end
165 + #end
162 166
163 167 when "php"
164 168 command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]}"
165 169 if system(command, err: params[:message_file])
166 170 File.open(params[:output_file],"w") do |out_file|
167 171 out_file.puts "#!#{PHP_INTERPRETER}"
168 172 File.open(params[:source_file],"r").each do |line|
169 173 out_file.print line
170 174 end
171 175 end
172 176 File.chmod(0755, params[:output_file])
173 177 end
174 178
179 + when "haskell"
180 + command = "#{HASKELL_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{HASKELL_OPTIONS}"
181 + system(command, err: params[:message_file])
182 +
175 183 else
176 184 talk("ERROR: Invalid language specified!")
177 185 open(params[:message_file],"w") do |f|
178 186 f.puts "ERROR: Invalid language specified!"
179 187 end
180 188 exit(127)
181 189 end
182 190
183 191 # Report success or failure.
184 192 if FileTest.exists? params[:output_file]
185 193 talk "Compilation was successful!"
186 194 else
187 195 talk "ERROR: Something was wrong during the compilation!"
188 196 end
@@ -8,97 +8,97
8 8 end
9 9 if ENV['GRADER_LOGGING']!=nil
10 10 log_fname = ENV['GRADER_LOGGING']
11 11 fp = File.open(log_fname,"a")
12 12 fp.puts("judge: #{Time.new.strftime("%H:%M")} #{str}")
13 13 fp.close
14 14 end
15 15 end
16 16
17 17 problem_home = ENV['PROBLEM_HOME']
18 18
19 19 def execute(command, error_message="")
20 20 if not system(command)
21 21 msg = "ERROR: #{error_message}"
22 22 log msg
23 23 raise(msg)
24 24 end
25 25 end
26 26
27 27 def call_and_log(error_message)
28 28 begin
29 29 yield
30 30 rescue
31 31 msg = "ERROR: #{error_message}"
32 32 log msg
33 33 raise msg
34 34 end
35 35 end
36 36
37 37 def clear_and_create_empty_dir(dir)
38 38 FileUtils.rm_rf(dir, :secure => true)
39 39 call_and_log("Cannot make directory #{dir}.") { FileUtils.mkdir(dir) }
40 40 end
41 41
42 42 # ARGV[0] --- language
43 43 # ARGV[1] --- program source file
44 44 # ARGV[2] --- test result directory
45 45 # ARGV[3] --- sandbox directory
46 46
47 47 if ARGV.length < 2 || ARGV.length > 4
48 48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
49 49 puts " <sandbox-directory> is defaulted to ./sandbox"
50 50 puts " <test-result-directory> is defaulted to ./test-result"
51 51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
52 52 exit(127)
53 53 end
54 54
55 55 language = ARGV[0]
56 - if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby" && language != "python" && language != "php"
56 + if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby" && language != "python" && language != "php" && language != "haskell"
57 57 log "You specified a language that is not supported: #{language}."
58 58 exit(127)
59 59 end
60 60
61 61 source_file = ARGV[1]
62 62 ENV['SOURCE_NAME'] = source_file
63 63 if File.exist?(source_file) == false
64 64 log "The source file does not exist."
65 65 exit(127)
66 66 end
67 67
68 68 log "Making test result and sandbox directories..."
69 69
70 70 current_dir = FileUtils.pwd
71 71 current_dir.strip!
72 72
73 73 if ARGV.length >= 3
74 74 test_result_dir = ARGV[2]
75 75 else
76 76 test_result_dir = "#{current_dir}/test-result"
77 77 end
78 78
79 79 log "Test result directory: #{test_result_dir}"
80 80 clear_and_create_empty_dir(test_result_dir)
81 81
82 82 if ARGV.length >= 4
83 83 sandbox_dir = ARGV[3]
84 84 else
85 85 sandbox_dir = "#{current_dir}/sandbox"
86 86 end
87 87 log "Sandbox directory: #{sandbox_dir}"
88 88 clear_and_create_empty_dir(sandbox_dir)
89 89
90 90 # Compile
91 91 log
92 92 log "Compiling..."
93 93 call_and_log("Cannot copy the source file to #{sandbox_dir}") {
94 94 FileUtils.cp(source_file, sandbox_dir)
95 95 }
96 96 begin
97 97 Dir.chdir sandbox_dir
98 98 rescue
99 99 log "ERROR: Cannot change directory to #{sandbox_dir}."
100 100 exit(127)
101 101 end
102 102 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
103 103 compile_message = open("compiler_message").read
104 104 compile_message.strip!
@@ -47,113 +47,116
47 47 require "#{problem_home}/script/test_dsl.rb"
48 48 load "#{problem_home}/test_cases/all_tests.cfg"
49 49 problem = Problem.get_instance
50 50
51 51 sandbox_dir = Dir.getwd
52 52
53 53 if problem.well_formed? == false
54 54 log "The problem specification is not well formed."
55 55 exit(127)
56 56 end
57 57
58 58 # Check if the test number is okay.
59 59 if test_num <= 0 || test_num > problem.num_tests
60 60 log "You have specified a wrong test number."
61 61 exit(127)
62 62 end
63 63
64 64 #####################################
65 65 # Set the relavant file names here. #
66 66 #####################################
67 67
68 68 input_file_name = "#{problem_home}/test_cases/#{test_num}/input-#{test_num}.txt"
69 69
70 70 #####################################
71 71
72 72 time_limit = problem.get_time_limit test_num
73 73 mem_limit = problem.get_mem_limit(test_num) * 1024
74 74
75 75 # Copy the input file.
76 76 #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .`
77 77
78 78 # check if box is there, if not, compile it!
79 79 if !File.exists?("#{problem_home}/script/box")
80 80 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
81 81 compile_box("#{problem_home}/script/box.cc",
82 82 "#{problem_home}/script/box")
83 83 end
84 84
85 85 # Hide PROBLEM_HOME
86 86 ENV['PROBLEM_HOME'] = nil
87 87 ENV['SOURCE_NAME'] = nil
88 88
89 89 # Run the program.
90 90 #run_command = "/usr/bin/time -f \"#{time_output_format}\" 2>run_result #{problem_home}/script/box_new -a 2 -f -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name}"
91 91 #
92 92
93 93 JAVA_OPTION = "-s set_robust_list -s futex -s clone -s getppid -s clone -s wait4 -p /usr/bin/ -p ./"
94 94 RUBY_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /lib64/ -p /dev/urandom -p #{sandbox_dir}/#{program_name} -p #{sandbox_dir}/ -s set_robust_list -s sched_getaffinity -s clock_gettime -s sigaltstack -s pipe2 -s clone -s futex -s openat -s pipe"
95 - PYTHON_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /usr/bin/ -p /lib64/ -p /dev/urandom -p /usr/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p #{sandbox_dir}/#{source_name} -p /proc/mounts -s statfs -s set_robust_list -s openat -s recvmsg -s connect -s socket -s sendto -s futex -s sigaltstack -E PYTHONNOUSERSITE=yes"
95 + PYTHON_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /usr/bin/ -p /lib64/ -p /dev/urandom -p /usr/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p #{sandbox_dir}/#{source_name} -p /proc/sys/crypto/fips_enabled -p /proc/self/status -p /proc/mounts -p /var/lib/dpkg/status -s statfs -s set_robust_list -s openat -s sysinfo -s recvmsg -s connect -s socket -s sendto -s futex -s sigaltstack -s getrandom -E PYTHONNOUSERSITE=yes"
96 96 PHP_OPTION = "-p /usr/lib64/ -p/lib64/ -p /usr/bin/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p /usr/share/ -s setfsuid -s setfsgid -s openat -s set_robust_list -s futex -s clone -s socket -s connect"
97 + HASKELL_OPTION = "-s set_robust_list -s clock_gettime -s sysinfo -s timer_create -s timer_settime -s futex -s timer_delete"
97 98
98 99 case language
99 100 when "java"
100 101 # for java, extract the classname
101 102 # wne have to add additional systemcall and we don't check the mem limit (dunno how to fix...)
102 103 classname = 'DUMMY'
103 104 File.open(program_name,"r").each do |line|
104 105 classname = line
105 106 end
106 107 #for java, we cannot really check the memory limit...
107 108 run_command = "#{problem_home}/script/box -a 3 -f -T -t #{time_limit} #{JAVA_OPTION} -i #{input_file_name} -o output.txt /usr/bin/java -A -Xmx#{mem_limit}k -A #{classname} "
108 109 when "ruby"
109 110 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{RUBY_OPTION} -i #{input_file_name} -o output.txt /usr/bin/ruby #{program_name} "
110 111 when "python"
111 112 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128 * 1024,mem_limit].max} #{PYTHON_OPTION} -i #{input_file_name} -o output.txt /usr/bin/python3 #{program_name} "
113 + when "haskell"
114 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{[512 * 1024,mem_limit].max} #{HASKELL_OPTION} -i #{input_file_name} -o output.txt #{program_name} "
112 115 when "php"
113 116 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128 * 1024,mem_limit].max} #{PHP_OPTION} -i #{input_file_name} -o output.txt /usr/bin/php -A -d -A memory_limit=#{mem_limit}k -A #{program_name} "
114 117 else # for c++, pascal, we do the normal checking
115 118 run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name} "
116 119 end
117 120
118 121
119 122 log "Running test #{test_num}..."
120 123 log run_command
121 124 log
122 125 system(run_command,err: 'run_result')
123 126
124 127 # Restore PROBLEM_HOME
125 128 ENV['PROBLEM_HOME'] = problem_home
126 129
127 130 # Create the result file.
128 131 result_file = File.new("result", "w")
129 132 comment_file = File.new("comment", "w")
130 133
131 134 # Check if the program actually produced any output.
132 135 run_result_file = File.new("run_result", "r")
133 136 run_result = run_result_file.readlines
134 137 run_result_file.close
135 138
136 139 run_stat = run_result[run_result.length-1]
137 140 running_time = extract_time(run_stat)
138 141
139 142 report = lambda{ |status, points, comment|
140 143 result_file.write status.strip
141 144 result_file.write "\n"
142 145 result_file.write points.to_s.strip
143 146 result_file.write "\n"
144 147 result_file.write run_stat.strip
145 148 result_file.write "\n"
146 149 result_file.close
147 150 FileUtils.rm "run_result"
148 151 # `rm output.txt` --- keep the output
149 152
150 153 comment_file.write comment
151 154
152 155 # added for debuggin --- jittat
153 156 comment_file.write "--run-result--\n"
154 157 run_result.each do |l|
155 158 comment_file.write l
156 159 end
157 160
158 161 comment_file.close
159 162
You need to be logged in to leave comments. Login now