Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dmoj/executors/C.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class Executor(GCCMixin, CExecutor):
command = 'gcc'
std = 'c99'
ext_priority = 1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use a smarter numbering scheme? Like 111 for Clang C11, 10099 for GCC C99, 10111 for C11, 11114 for C++14, etc.? This way, we don't need to shuffle all the numbers to add a new runtime...


test_program = """
#include <stdio.h>
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/C11.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(GCCMixin, CExecutor):
command = 'gcc11'
std = 'c11'
command_paths = ['gcc']
ext_priority = 2

test_program = """
#include <stdio.h>
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/C23.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(GCCMixin, CExecutor):
command = 'gcc23'
std = 'c23'
command_paths = ['gcc']
ext_priority = 4

test_program = """
#include <stdio.h>
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CLANG.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(ClangMixin, CExecutor):
command = 'clang'
std = 'c11'
command_paths = [f'clang-{i}' for i in CLANG_VERSIONS] + ['clang']
ext_priority = 3

test_program = """
#include <stdio.h>
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CLPP14.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(ClangMixin, CPPExecutor):
command = 'clang++'
std = 'c++14'
command_paths = [f'clang++-{i}' for i in CLANG_VERSIONS] + ['clang++']
ext_priority = 4

test_program = """
#include <iostream>
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CLPP17.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(ClangMixin, CPPExecutor):
command = 'clang++'
std = 'c++17'
command_paths = [f'clang++-{i}' for i in CLANG_VERSIONS] + ['clang++']
ext_priority = 6

test_program = """
#include <iostream>
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CLPP20.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(ClangMixin, CPPExecutor):
command = 'clang++'
std = 'c++20'
command_paths = [f'clang++-{i}' for i in CLANG_VERSIONS] + ['clang++']
ext_priority = 8

test_program = """
#include <iostream>
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CLPP23.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(ClangMixin, CPPExecutor):
command = 'clang++'
std = 'c++23'
command_paths = [f'clang++-{i}' for i in CLANG_VERSIONS] + ['clang++']
ext_priority = 10

test_program = """
#include <iostream>
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CPP03.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class Executor(GCCMixin, CPPExecutor):
command = 'g++'
std = 'c++03'
ext_priority = 1
test_program = """
#include <iostream>

Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CPP11.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(GCCMixin, CPPExecutor):
command = 'g++11'
command_paths = ['g++-5', 'g++-4.9', 'g++-4.8', 'g++']
std = 'c++11'
ext_priority = 2
test_program = """
#include <iostream>

Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CPP14.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(GCCMixin, CPPExecutor):
command = 'g++14'
command_paths = ['g++-5', 'g++']
std = 'c++14'
ext_priority = 3
test_program = """
#include <iostream>

Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CPP17.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(GCCMixin, CPPExecutor):
command = 'g++17'
command_paths = ['g++-7', 'g++']
std = 'c++17'
ext_priority = 5
test_program = """
#include <iostream>

Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CPP20.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(GCCMixin, CPPExecutor):
command = 'g++20'
command_paths = ['g++-11', 'g++']
std = 'c++20'
ext_priority = 7
test_program = """
#include <iostream>

Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/CPP23.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(GCCMixin, CPPExecutor):
command = 'g++23'
command_paths = ['g++-13', 'g++']
std = 'c++23'
ext_priority = 9
test_program = """
#include <iostream>

Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/GAS32.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class Executor(PlatformX86Mixin, GASExecutor):
as_name = 'as_x86'
ext_priority = 1

test_program = r""".intel_syntax noprefix

Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/GAS64.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class Executor(PlatformX64Mixin, GASExecutor):
as_name = 'as_x64'
ext_priority = 2

test_program = r""".intel_syntax noprefix

Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/JAVA.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(JavacExecutor):
compiler = 'javac'
vm = 'java'
jvm_regex = r'(?:java-|openjdk)(?:9|[1-9][0-9]+)'
ext_priority = 2

test_program = """\
import java.io.IOException;
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/JAVA8.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Executor(JavacExecutor):
compiler = 'javac8'
vm = 'java8'
jvm_regex = r'java-8-|jdk-8-|openjdk8|oracle-java8'
ext_priority = 1

test_program = """\
import java.io.IOException;
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/NASM.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class Executor(PlatformX86Mixin, NASMExecutor):
nasm_format = 'elf32'
ext_priority = 1

test_program = """\
section .text
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/NASM64.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class Executor(PlatformX64Mixin, NASMExecutor):
nasm_format = 'elf64'
ext_priority = 2

test_program = """\
section .text
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/PY2.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(PythonExecutor):
command = 'python'
command_paths = ['python2.7', 'python2', 'python']
pygments_traceback_lexer = 'py2tb'
ext_priority = 1
test_program = """
import sys
if sys.version_info.major == 2:
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/PY3.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class Executor(PythonExecutor):
command = 'python3'
command_paths = [f'python{i}' for i in ['3.6', '3.5', '3.4', '3.3', '3.2', '3.1', '3']]
pygments_traceback_lexer = 'py3tb'
ext_priority = 3
test_program = """
import sys
if sys.version_info.major == 3:
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/PYPY.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
class Executor(PythonExecutor):
command = 'pypy'
pygments_traceback_lexer = 'py2tb'
ext_priority = 2
test_program = """
import sys
if sys.version_info.major == 2:
Expand Down
1 change: 1 addition & 0 deletions dmoj/executors/PYPY3.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class Executor(PYPYExecutor):
command = 'pypy3'
pygments_traceback_lexer = 'py3tb'
ext_priority = 4
test_program = """
import sys
if sys.version_info.major == 3:
Expand Down
4 changes: 2 additions & 2 deletions dmoj/executors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ def by_ext(ext: str) -> Any:
if name.lower() == ext:
return executor

for executor in sorted(executors.values(), key=lambda executor: executor.Executor.name):
if executor.Executor.ext == ext:
for executor in sorted(executors.values(), key=lambda executor: executor.Executor.ext_priority, reverse=True):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we specify a fixed order? Like lexicographically increasing by executor name? I don't want any flaky behaviour and dict value order isn't guaranteed...

if ext in executor.Executor.get_valid_exts():
return executor

raise KeyError('no executor for extension "%s"' % ext)
Expand Down
12 changes: 11 additions & 1 deletion dmoj/executors/base_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import sys
import tempfile
import traceback
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, Union

from dmoj.cptbox import IsolateTracer, TracedPopen, syscalls
from dmoj.cptbox.filesystem_policies import ExactDir, ExactFile, FilesystemAccessRule, RecursiveDir
Expand Down Expand Up @@ -120,6 +120,7 @@ class BaseExecutor(metaclass=ExecutorMeta):
test_memory = env.selftest_memory_limit
version_regex = re.compile(r'.*?(\d+(?:\.\d+)+)', re.DOTALL)
source_filename_format = '{problem_id}.{ext}'
ext_priority = 0 # When there are multiple versions of a similar runtime, bigger is newer

address_grace = 65536
data_grace = 0
Expand Down Expand Up @@ -483,3 +484,12 @@ def get_find_first_mapping(cls) -> Optional[Dict[str, List[str]]]:
@classmethod
def autoconfig(cls) -> AutoConfigOutput:
return cls.autoconfig_find_first(cls.get_find_first_mapping())

@classmethod
def get_valid_exts(cls) -> Sequence[str]:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why this is a method and not just a class variable?

# This exists because sometimes we want to recognize more extensions than just `ext` for auxiliary files
return (cls.ext,)

@classmethod
def supports_multifile(cls) -> bool:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, class variable.

return False
16 changes: 15 additions & 1 deletion dmoj/executors/c_like_executor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import re
from collections import deque
from typing import Dict, List, Optional, Type
from typing import Dict, List, Optional, Sequence, Type

from dmoj.cptbox import TracedPopen
from dmoj.executors.base_executor import AutoConfigOutput, AutoConfigResult, VersionFlags
Expand Down Expand Up @@ -139,6 +139,10 @@ def initialize(cls) -> bool:
cls.has_color = versions is not None and versions[0][1] is not None and versions[0][1] > (4, 9)
return res

@classmethod
def supports_multifile(cls) -> bool:
return True


class GCCMixin(CLikeExecutor):
arch: str = 'gcc_target_arch'
Expand All @@ -161,6 +165,11 @@ def get_flags(self) -> List[str]:
def get_version_flags(cls, command: str) -> List[VersionFlags]:
return ['--version']

def create_files(self, problem_id: str, source_code: bytes, *args, **kwargs) -> None:
super().create_files(problem_id, source_code, *args, **kwargs)
# Clang/++ will complain if you pass header files, so we strip them out
self.source_paths = [source for source in self.source_paths if source.partition('.')[-1] not in ('h', 'hpp')]


class CExecutor(CLikeExecutor):
ext: str = 'c'
Expand All @@ -170,3 +179,8 @@ class CExecutor(CLikeExecutor):
class CPPExecutor(CLikeExecutor):
ext: str = 'cpp'
is_signature_gradable = True

@classmethod
def get_valid_exts(cls) -> Sequence[str]:
# Recognize both `cpp` and `cc` as valid C++ extensions for auxiliary files
return 'cpp', 'cc'
2 changes: 1 addition & 1 deletion dmoj/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def _run_generator(self, gen: Union[str, ConfigNode], args: Optional[Iterable[st
time_limit = env.generator_time_limit
memory_limit = env.generator_memory_limit
compiler_time_limit = env.generator_compiler_time_limit
lang = None # Default to C/C++
lang = None # Default to autodetection

base = get_problem_root(self.problem.id)
assert base is not None
Expand Down
24 changes: 4 additions & 20 deletions dmoj/utils/helper_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,6 @@ def compile_with_auxiliary_files(
with open(filename, 'rb') as f:
sources[os.path.basename(filename)] = f.read()

def find_runtime(*languages):
for grader in languages:
if grader in executors.executors:
return grader
return None

use_cpp = any(map(lambda name: os.path.splitext(name)[1] in ['.cpp', '.cc'], filenames))
use_c = any(map(lambda name: os.path.splitext(name)[1] in ['.c'], filenames))
if not lang:
if use_cpp:
lang = find_runtime('CPP20', 'CPP17', 'CPP14', 'CPP11', 'CPP03')
elif use_c:
lang = find_runtime('C11', 'C')

# TODO: remove above code once `from_filename` is smart enough to
# prioritize newer versions of runtimes
if not lang:
for filename in filenames:
try:
Expand All @@ -69,15 +53,15 @@ def find_runtime(*languages):
kwargs['compiler_time_limit'] = compiler_time_limit

if hasattr(executor, 'flags'):
kwargs['flags'] = flags + list(executor.flags)
kwargs['flags'] = flags + executor.flags

# Optimize the common case.
if use_cpp or use_c:
# Check if the executor supports multifile compilation
if executor.supports_multifile():
# Some auxiliary files (like those using testlib.h) take an extremely long time to compile, so we cache them.
executor = executor('_aux_file', None, aux_sources=sources, cached=True, unbuffered=unbuffered, **kwargs)
else:
if len(sources) > 1:
raise InternalError('non-C/C++ auxiliary programs cannot be multi-file')
raise InternalError(f'{lang} auxiliary programs cannot be multi-file')
executor = executor('_aux_file', list(sources.values())[0], cached=True, unbuffered=unbuffered, **kwargs)

return executor
Expand Down
5 changes: 3 additions & 2 deletions testsuite/bridged_interactor/interactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@ int main(int argc, char *argv[]) {
int N, guesses = 0;
long long guess;
fscanf(input_file, "%d", &N);
while (guess != N) {
while (true) {
read(&guess);
guesses++;
if (guess == N) {
puts("OK");
break;
} else if (guess > N) {
puts("FLOATS");
} else {
puts("SINKS");
}
fflush(stdout);
guesses++;
}
if (guesses <= 31)
return 0; // AC
Expand Down
5 changes: 3 additions & 2 deletions testsuite/bridged_interactor_noflush/interactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ int main(int argc, char *argv[]) {
int N, guesses = 0;
long long guess;
fscanf(input_file, "%d", &N);
while (guess != N) {
while (true) {
read(&guess);
guesses++;
if (guess == N) {
puts("OK");
break;
} else if (guess > N) {
puts("FLOATS");
} else {
puts("SINKS");
}
guesses++;
}
if (guesses <= 31)
return 0; // AC
Expand Down
1 change: 1 addition & 0 deletions testsuite/siggrade/tests/clang_signature_grading/sigtest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bool is_valid(int n) { return n == 1; }
5 changes: 5 additions & 0 deletions testsuite/siggrade/tests/clang_signature_grading/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
language: CLANG
time: 2
memory: 65536
source: sigtest.c
expect: AC