Show More
Commit Description:
autonew skips submissions with bad problems, forbids getch, better compiler msg when preprocessing fails, reports compile error when the executable is too large (100MB)
Commit Description:
autonew skips submissions with bad problems, forbids getch, better compiler msg when preprocessing fails, reports compile error when the executable is too large (100MB)
References:
File last commit:
Show/Diff file:
Action:
std-script/compile
| 141 lines
| 3.7 KiB
| text/plain
| TextLexer
|
|
r107 | #!/usr/bin/ruby | ||
require 'fileutils' | ||||
|
r0 | |||
############################## | ||||
# | ||||
# Standard Compile Script | ||||
# | ||||
# Supported compilers: | ||||
|
r53 | # gcc, g++, and fpc. | ||
|
r0 | # | ||
############################## | ||||
|
r107 | def talk(msg) | ||
if ENV['TALKATIVE']!=nil | ||||
puts str | ||||
end | ||||
|
r128 | |||
|
r107 | if ENV['GRADER_LOGGING']!=nil | ||
log_fname = ENV['GRADER_LOGGING'] | ||||
fp = File.open(log_fname,"a") | ||||
|
r115 | fp.puts("run: #{Time.new.strftime("%H:%M")} #{msg}") | ||
|
r107 | fp.close | ||
end | ||||
end | ||||
|
r22 | |||
|
r111 | C_COMPILER = "gcc" | ||
CPLUSPLUS_COMPILER = "g++" | ||||
PASCAL_COMPILER = "fpc" | ||||
|
r0 | |||
|
r107 | C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall" | ||
CPLUSPLUS_OPTIONS = "-O2 -s -static -DCONTEST -lm -Wall" | ||||
PASCAL_OPTIONS = "-O1 -XS -dCONTEST" | ||||
|
r0 | |||
# Check for the correct number of arguments. Otherwise, print usage. | ||||
|
r107 | if ARGV.length == 0 or ARGV.length > 4 | ||
puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]" | ||||
puts | ||||
puts "<source-file> is defaulted to \"source\"." | ||||
puts "<output-file> is defaulted to \"a.out\"." | ||||
puts "<message-file> is defaulted to \"compiler_message\"." | ||||
puts | ||||
exit(127) | ||||
end | ||||
|
r0 | |||
|
r107 | PARAMS = { | ||
:source_file => [1,'source'], | ||||
:output_file => [2,'a.out'], | ||||
:message_file => [3,'compiler_message'] | ||||
} | ||||
|
r0 | |||
|
r107 | params = {} | ||
params[:prog_lang] = ARGV[0] | ||||
PARAMS.each_key do |param_name| | ||||
index, default = PARAMS[param_name] | ||||
if ARGV.length > index | ||||
params[param_name] = ARGV[index] | ||||
else | ||||
params[param_name] = default | ||||
end | ||||
talk "#{param_name}: #{params[param_name]}" | ||||
end | ||||
|
r0 | |||
# Remove any remaining output files or message files. | ||||
|
r107 | if FileTest.exists? params[:output_file] | ||
FileUtils.rm(params[:output_file]) | ||||
end | ||||
if FileTest.exists? params[:message_file] | ||||
FileUtils.rm(params[:message_file]) | ||||
end | ||||
|
r0 | |||
# Check if the source file exists before attempt compiling. | ||||
|
r107 | if !FileTest.exists? params[:source_file] | ||
talk("ERROR: The source file does not exist!") | ||||
open(params[:message_file],"w") do |f| | ||||
f.puts "ERROR: The source file did not exist." | ||||
end | ||||
exit(127) | ||||
end | ||||
|
r0 | |||
|
r119 | if params[:prog_lang]=='cpp': | ||
params[:prog_lang] = 'c++' | ||||
end | ||||
|
r132 | forbidden_functions = ['system', 'fopen', 'freopen', 'open', 'remove', 'rename', 'getch'] | ||
|
r128 | redefine_list = [] | ||
forbidden_count = 0 | ||||
forbidden_key = (rand(8999) + 1000).to_s | ||||
forbidden_functions.each do |f| | ||||
redefine_list << "-D#{f}=forbidden#{forbidden_key}#{forbidden_count}" | ||||
forbidden_count += 1 | ||||
end | ||||
redefine_str = redefine_list.join ' ' | ||||
puts redefine_str | ||||
|
r0 | # Compile. | ||
|
r107 | case params[:prog_lang] | ||
when "c" | ||||
|
r132 | command = "#{C_COMPILER} -E #{params[:source_file]} -o source_prep.c 2> #{params[:message_file]}" | ||
|
r128 | system(command) | ||
|
r132 | if FileTest.exist? "source_prep.c" | ||
command = "#{C_COMPILER} source_prep.c #{redefine_str} -o #{params[:output_file]} #{C_OPTIONS} 2> #{params[:message_file]}" | ||||
system(command) | ||||
end | ||||
|
r107 | |||
when "c++" | ||||
|
r132 | command = "#{CPLUSPLUS_COMPILER} -E #{params[:source_file]} -o source_prep.cpp 2> #{params[:message_file]}" | ||
|
r128 | system(command) | ||
|
r132 | if FileTest.exist? "source_prep.cpp" | ||
command = "#{CPLUSPLUS_COMPILER} #{redefine_str} source_prep.cpp -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS} 2> #{params[:message_file]}" | ||||
system(command) | ||||
end | ||||
|
r107 | when "pas" | ||
command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS} > #{params[:message_file]}" | ||||
system(command) | ||||
FileUtils.mv("output", params[:output_file]) | ||||
else | ||||
talk("ERROR: Invalid language specified!") | ||||
open(params[:message_file],"w") do |f| | ||||
f.puts "ERROR: Invalid language specified!" | ||||
end | ||||
exit(127) | ||||
end | ||||
|
r0 | |||
# Report success or failure. | ||||
|
r107 | if FileTest.exists? params[:output_file] | ||
|
r132 | talk "Compilation was successful!" | ||
if File.size(params[:output_file]) > 100000000 | ||||
talk "But the executable is too big." | ||||
open(params[:message_file],"w+") do |f| | ||||
f.puts "Executable is too large." | ||||
end | ||||
File.delete(params[:output_file]) | ||||
end | ||||
|
r0 | else | ||
|
r107 | talk "ERROR: Something was wrong during the compilation!" | ||
end | ||||