Skip to content

Commit

Permalink
Additional compilation flags (#200)
Browse files Browse the repository at this point in the history
* Change weak flag option to compile mode
Added flages used by oioioi as an option

* Minor changes and additional test

* Update descriptions

* Add aliases for compile_mode arguments
  • Loading branch information
adespawn authored Mar 7, 2024
1 parent 48c560b commit 73ca1fe
Show file tree
Hide file tree
Showing 24 changed files with 102 additions and 41 deletions.
4 changes: 2 additions & 2 deletions src/sinol_make/commands/export/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def generate_input_tests(self):
if ingen_exists(self.task_id):
ingen_path = get_ingen(self.task_id)
ingen_path = os.path.join(prog_dir, os.path.basename(ingen_path))
ingen_exe = compile_ingen(ingen_path, self.args, self.args.weak_compilation_flags)
ingen_exe = compile_ingen(ingen_path, self.args, self.args.compile_mode)
if not run_ingen(ingen_exe, in_dir):
util.exit_with_error('Failed to run ingen.')

Expand All @@ -75,7 +75,7 @@ def generate_output_files(self):
if len(outputs) > 0:
outgen = OutgenCommand()
correct_solution_exe = compile_correct_solution(get_correct_solution(self.task_id), self.args,
self.args.weak_compilation_flags)
self.args.compile_mode)
outgen.args = self.args
outgen.correct_solution_exe = correct_solution_exe
outgen.generate_outputs(outputs)
Expand Down
2 changes: 1 addition & 1 deletion src/sinol_make/commands/ingen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def run(self, args: argparse.Namespace):
util.change_stack_size_to_unlimited()
self.ingen = get_ingen(self.task_id, args.ingen_path)
print(util.info(f'Using ingen file {os.path.basename(self.ingen)}'))
self.ingen_exe = compile_ingen(self.ingen, self.args, self.args.weak_compilation_flags)
self.ingen_exe = compile_ingen(self.ingen, self.args, self.args.compile_mode)

if run_ingen(self.ingen_exe):
print(util.info('Successfully generated input files.'))
Expand Down
4 changes: 2 additions & 2 deletions src/sinol_make/commands/ingen/ingen_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def get_ingen(task_id, ingen_path=None):
return correct_ingen


def compile_ingen(ingen_path: str, args: argparse.Namespace, weak_compilation_flags=False):
def compile_ingen(ingen_path: str, args: argparse.Namespace, compilation_flags='default'):
"""
Compiles ingen and returns path to compiled executable.
If ingen_path is shell script, then it will be returned.
Expand All @@ -57,7 +57,7 @@ def compile_ingen(ingen_path: str, args: argparse.Namespace, weak_compilation_fl

compilers = compiler.verify_compilers(args, [ingen_path])
ingen_exe, compile_log_path = compile.compile_file(ingen_path, package_util.get_executable(ingen_path), compilers,
weak_compilation_flags, use_fsanitize=True)
compilation_flags, use_fsanitize=True)

if ingen_exe is None:
compile.print_compile_log(compile_log_path)
Expand Down
2 changes: 1 addition & 1 deletion src/sinol_make/commands/inwer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def configure_subparser(self, subparser: argparse.ArgumentParser):
add_compilation_arguments(parser)

def compile_inwer(self, args: argparse.Namespace):
self.inwer_executable, compile_log_path = inwer_util.compile_inwer(self.inwer, args, args.weak_compilation_flags)
self.inwer_executable, compile_log_path = inwer_util.compile_inwer(self.inwer, args, args.compile_mode)
if self.inwer_executable is None:
util.exit_with_error('Compilation failed.', lambda: compile.print_compile_log(compile_log_path))
else:
Expand Down
4 changes: 2 additions & 2 deletions src/sinol_make/commands/inwer/inwer_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ def get_inwer_path(task_id: str, path = None) -> Union[str, None]:
return None


def compile_inwer(inwer_path: str, args: argparse.Namespace, weak_compilation_flags=False):
def compile_inwer(inwer_path: str, args: argparse.Namespace, compilation_flags='default'):
"""
Compiles inwer and returns path to compiled executable and path to compile log.
"""
compilers = compiler.verify_compilers(args, [inwer_path])
return compile.compile_file(inwer_path, package_util.get_executable(inwer_path), compilers, weak_compilation_flags,
return compile.compile_file(inwer_path, package_util.get_executable(inwer_path), compilers, compilation_flags,
use_fsanitize=True)


Expand Down
2 changes: 1 addition & 1 deletion src/sinol_make/commands/outgen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def run(self, args: argparse.Namespace):
print(util.info('All output files are up to date.'))
else:
self.correct_solution_exe = compile_correct_solution(self.correct_solution, self.args,
self.args.weak_compilation_flags)
self.args.compile_mode)
self.generate_outputs(outputs_to_generate)
with open(os.path.join(os.getcwd(), 'in', '.md5sums'), 'w') as f:
yaml.dump(md5_sums, f)
Expand Down
4 changes: 2 additions & 2 deletions src/sinol_make/commands/outgen/outgen_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ def get_correct_solution(task_id):
return correct_solution[0]


def compile_correct_solution(solution_path: str, args: argparse.Namespace, weak_compilation_flags=False):
def compile_correct_solution(solution_path: str, args: argparse.Namespace, compilation_flags='default'):
"""
Compiles correct solution and returns path to compiled executable.
"""
compilers = compiler.verify_compilers(args, [solution_path])
correct_solution_exe, compile_log_path = compile.compile_file(solution_path, package_util.get_executable(solution_path), compilers,
weak_compilation_flags)
compilation_flags)
if correct_solution_exe is None:
util.exit_with_error('Failed compilation of correct solution.',
lambda: compile.print_compile_log(compile_log_path))
Expand Down
2 changes: 1 addition & 1 deletion src/sinol_make/commands/run/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ def compile(self, solution, use_extras = False, is_checker = False):

try:
with open(compile_log_file, "w") as compile_log:
compile.compile(source_file, output, self.compilers, compile_log, self.args.weak_compilation_flags,
compile.compile(source_file, output, self.compilers, compile_log, self.args.compile_mode,
extra_compilation_args, extra_compilation_files, is_checker=is_checker)
print(util.info("Compilation of file %s was successful."
% package_util.get_file_name(solution)))
Expand Down
30 changes: 18 additions & 12 deletions src/sinol_make/helpers/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import shutil
import stat
import subprocess
import yaml

import sinol_make.helpers.compiler as compiler
from sinol_make import util
Expand All @@ -14,15 +13,15 @@
from sinol_make.structs.compiler_structs import Compilers


def compile(program, output, compilers: Compilers = None, compile_log = None, weak_compilation_flags = False,
extra_compilation_args = None, extra_compilation_files = None, is_checker = False, use_fsanitize = False):
def compile(program, output, compilers: Compilers = None, compile_log=None, compilation_flags='default',
extra_compilation_args=None, extra_compilation_files=None, is_checker=False, use_fsanitize=False):
"""
Compile a program.
:param program: Path to the program to compile
:param output: Path to the output file
:param compilers: Compilers object
:param compile_log: File to write the compilation log to
:param weak_compilation_flags: If True, disable all warnings
:param compilation_flags: Group of compilation flags to use
:param extra_compilation_args: Extra compilation arguments
:param extra_compilation_files: Extra compilation files
:param is_checker: Set to True if compiling a checker. This will remove all cached test results.
Expand Down Expand Up @@ -53,30 +52,37 @@ def compile(program, output, compilers: Compilers = None, compile_log = None, we
for file in extra_compilation_files:
shutil.copy(file, os.path.join(os.path.dirname(output), os.path.basename(file)))

gcc_compilation_flags = ' -Werror -Wall -Wextra -Wshadow -Wconversion -Wno-unused-result -Wfloat-equal'
if weak_compilation_flags:
gcc_compilation_flags = ''
if compilation_flags == 'weak' or compilation_flags == 'w':
compilation_flags = 'weak'
gcc_compilation_flags = '' # Disable all warnings
elif compilation_flags == 'oioioi' or compilation_flags == 'o':
gcc_compilation_flags = ' -Wall -Wno-unused-result -Werror' # Same flags as oioioi
elif compilation_flags == 'default' or compilation_flags == 'd':
gcc_compilation_flags = ' -Werror -Wall -Wextra -Wshadow -Wconversion -Wno-unused-result -Wfloat-equal'
else:
util.exit_with_error(f'Unknown compilation flags group: {compilation_flags}')

if compilers is None:
compilers = Compilers()

ext = os.path.splitext(program)[1]
arguments = []
if ext == '.cpp':
arguments = [compilers.cpp_compiler_path or compiler.get_cpp_compiler_path(), program] + \
extra_compilation_args + ['-o', output] + \
f'--std=c++20 -O3 -lm{gcc_compilation_flags} -fdiagnostics-color'.split(' ')
if use_fsanitize and not weak_compilation_flags:
if use_fsanitize and compilation_flags != 'weak':
arguments += ['-fsanitize=address,undefined', '-fno-sanitize-recover']
elif ext == '.c':
arguments = [compilers.c_compiler_path or compiler.get_c_compiler_path(), program] + \
extra_compilation_args + ['-o', output] + \
f'--std=gnu99 -O3 -lm{gcc_compilation_flags} -fdiagnostics-color'.split(' ')
if use_fsanitize and not weak_compilation_flags:
if use_fsanitize and compilation_flags != 'weak':
arguments += ['-fsanitize=address,undefined', '-fno-sanitize-recover']
elif ext == '.py':
if sys.platform == 'win32' or sys.platform == 'cygwin':
# TODO: Make this work on Windows
print(util.error('Python is not supported on Windows'))
pass
else:
with open(output, 'w') as output_file, open(program, 'r') as program_file:
Expand Down Expand Up @@ -106,14 +112,14 @@ def compile(program, output, compilers: Compilers = None, compile_log = None, we
return True


def compile_file(file_path: str, name: str, compilers: Compilers, weak_compilation_flags = False, use_fsanitize = False) \
def compile_file(file_path: str, name: str, compilers: Compilers, compilation_flags='default', use_fsanitize=False) \
-> Tuple[Union[str, None], str]:
"""
Compile a file
:param file_path: Path to the file to compile
:param name: Name of the executable
:param compilers: Compilers object
:param weak_compilation_flags: Use weaker compilation flags
:param compilation_flags: Group of compilation flags to use
:param use_fsanitize: Whether to use fsanitize when compiling C/C++ programs. Sanitizes address and undefined behavior.
:return: Tuple of (executable path or None if compilation failed, log path)
"""
Expand All @@ -134,7 +140,7 @@ def compile_file(file_path: str, name: str, compilers: Compilers, weak_compilati
compile_log_path = paths.get_compilation_log_path(os.path.splitext(name)[0] + '.compile_log')
with open(compile_log_path, 'w') as compile_log:
try:
if compile(file_path, output, compilers, compile_log, weak_compilation_flags, extra_compilation_args,
if compile(file_path, output, compilers, compile_log, compilation_flags, extra_compilation_args,
extra_compilation_files, use_fsanitize=use_fsanitize):
return output, compile_log_path
except CompilationError:
Expand Down
24 changes: 15 additions & 9 deletions src/sinol_make/helpers/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ def add_compilation_arguments(parser: argparse.ArgumentParser):
gcc_versions = 'gcc'
gpp_versions = 'g++'

parser.add_argument('--c-compiler-path', dest='c_compiler_path', type=str, default=compiler.get_c_compiler_path(),
help=f'C compiler to use (default: {gcc_versions})')
parser.add_argument('--cpp-compiler-path', dest='cpp_compiler_path', type=str, default=compiler.get_cpp_compiler_path(),
help=f'C++ compiler to use (default: {gpp_versions})')
parser.add_argument('--python-interpreter-path', dest='python_interpreter_path', type=str, default=compiler.get_python_interpreter_path(),
parser.add_argument('--c-compiler-path', dest='c_compiler_path', type=str,
default=compiler.get_c_compiler_path(), help=f'C compiler to use (default: {gcc_versions})')
parser.add_argument('--cpp-compiler-path', dest='cpp_compiler_path', type=str,
default=compiler.get_cpp_compiler_path(), help=f'C++ compiler to use (default: {gpp_versions})')
parser.add_argument('--python-interpreter-path', dest='python_interpreter_path', type=str,
default=compiler.get_python_interpreter_path(),
help='Python interpreter to use (default: python3)')
parser.add_argument('--java-compiler-path', dest='java_compiler_path', type=str, default=compiler.get_java_compiler_path(),
help='Java compiler to use (default: javac)')
parser.add_argument('-W', '--weak-compilation-flags', dest='weak_compilation_flags', action='store_true',
help='disable all warning flags during C and C++ compilation')
parser.add_argument('--java-compiler-path', dest='java_compiler_path', type=str,
default=compiler.get_java_compiler_path(), help='Java compiler to use (default: javac)')
parser.add_argument('--compile-mode', '-C', dest='compile_mode', choices=['default', 'oioioi', 'weak', 'd', 'o', 'w'],
help='Warning flag groups used to compile C/C++ files. Available options:\n'
' default / d - uses default flags: \n'
' (-Wshadow -Wconversion -Wno-unused-result -Wfloat-equal) + oioioi flags\n'
' oioioi / o - uses the same flags as oioioi:\n'
' (-Wall -Wno-unused-result -Werror)'
' weak / w - disable all warning flags during C and C++ compilation', default='default')
2 changes: 1 addition & 1 deletion tests/commands/export/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def _create_package(tmpdir, path):
os.chdir(package_path)
command = get_command()
util.create_ins_outs(package_path)
command.args = argparse.Namespace(cpus=1, weak_compilation_flags=False,
command.args = argparse.Namespace(cpus=1, compile_mode='default',
cpp_compiler_path=compiler.get_cpp_compiler_path(),
c_compiler_path=None, python_interpreter_path=None,
java_compiler_path=None, export_ocen=False)
Expand Down
2 changes: 1 addition & 1 deletion tests/commands/export/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def get_command():
command = Command()
command.task_id = package_util.get_task_id()
command.args = argparse.Namespace(
weak_compilation_flags=False,
compile_mode='default',
c_compiler_path=compiler.get_c_compiler_path(),
cpp_compiler_path=compiler.get_cpp_compiler_path(),
python_interpreter_path=compiler.get_python_interpreter_path(),
Expand Down
25 changes: 22 additions & 3 deletions tests/commands/run/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,28 @@ def test_flag_solutions_multiple(capsys, create_package, time_tool):
@pytest.mark.parametrize("create_package", [get_weak_compilation_flags_package_path()], indirect=True)
def test_weak_compilation_flags(create_package):
"""
Test flag --weak-compilation-flags.
Test flag --compile-mode weak flag.
"""
parser = configure_parsers()
args = parser.parse_args(["run", "--time-tool", "time"])
command = Command()

with pytest.raises(SystemExit) as e:
command.run(args)

assert e.type == SystemExit
assert e.value.code == 1

args = parser.parse_args(["run", "--compile-mode", "weak", "--time-tool", "time"])
command = Command()
command.run(args)


@pytest.mark.parametrize("create_package", [get_oioioi_compilation_flags_package_path()], indirect=True)
def test_oioioi_compilation_flags(create_package):
"""
Test flag --compile-mode oioioi flag.
"""
package_path = create_package
parser = configure_parsers()
args = parser.parse_args(["run", "--time-tool", "time"])
command = Command()
Expand All @@ -263,7 +282,7 @@ def test_weak_compilation_flags(create_package):
assert e.type == SystemExit
assert e.value.code == 1

args = parser.parse_args(["run", "--weak-compilation-flags", "--time-tool", "time"])
args = parser.parse_args(["run", "--compile-mode", "oioioi", "--time-tool", "time"])
command = Command()
command.run(args)

Expand Down
2 changes: 1 addition & 1 deletion tests/commands/run/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_execution(create_package, time_tool):
def test_run_solutions(create_package, time_tool):
package_path = create_package
command = get_command(package_path)
command.args = argparse.Namespace(solutions_report=False, time_tool=time_tool, weak_compilation_flags=False,
command.args = argparse.Namespace(solutions_report=False, time_tool=time_tool, compile_mode='default',
hide_memory=False)
create_ins_outs(package_path)
command.tests = package_util.get_tests("abc", None)
Expand Down
2 changes: 1 addition & 1 deletion tests/commands/run/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ def get_command(path = None):

def set_default_args(command):
command.args = argparse.Namespace(
weak_compilation_flags=False,
compile_mode='default',
print_expected_scores=True,
)
11 changes: 11 additions & 0 deletions tests/packages/oioioi_flags/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
title: Package for testing --compile-mode oioioi flag
memory_limit: 16000
time_limit: 1000
sinol_task_id: oif
scores:
1: 100
sinol_expected_scores:
oif.cpp:
expected:
1: {points: 100, status: OK}
points: 100
Empty file.
1 change: 1 addition & 0 deletions tests/packages/oioioi_flags/in/oif1a.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1 1
Empty file.
Empty file.
1 change: 1 addition & 0 deletions tests/packages/oioioi_flags/out/oif1a.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2
10 changes: 10 additions & 0 deletions tests/packages/oioioi_flags/prog/oif.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <bits/stdc++.h>

using namespace std;

int main() {
long long a, b;
cin >> a >> b;
int c = a + b; // conversion from ‘long long int’ to ‘int’
cout << c << endl;
}
2 changes: 1 addition & 1 deletion tests/packages/wcf/config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
title: Package for testing --weak-compilation-flags
title: Package for testing --compile-mode weak
memory_limit: 16000
time_limit: 1000
scores:
Expand Down
7 changes: 7 additions & 0 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ def get_weak_compilation_flags_package_path():
return os.path.join(os.path.dirname(__file__), "packages", "wcf")


def get_oioioi_compilation_flags_package_path():
"""
Get path to package for testing oioioi compilation flags (/test/packages/oioioi_flags)
"""
return os.path.join(os.path.dirname(__file__), "packages", "oioioi_flags")


def get_inwer_package_path():
"""
Get path to package for inwer command (/test/packages/wer)
Expand Down

0 comments on commit 73ca1fe

Please sign in to comment.