Skip to content

Commit 2f6999a

Browse files
committed
support tests of SWIG python
1 parent 708860b commit 2f6999a

File tree

5 files changed

+119
-18
lines changed

5 files changed

+119
-18
lines changed

src/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,8 @@ JSON_DATA_TEXT = \"\"\"{
517517
\"libname_fmt\": \"${LIBNAME_FMT}\",
518518
\"rpath_fmt\": \"${RPATH_FMT}\",
519519
\"path_delimiter\": \"${OS_PATH_DELIMITER}\",
520-
\"exe_extension\": \"${EXE_EXTENSION}\"
520+
\"exe_extension\": \"${EXE_EXTENSION}\",
521+
\"source_include_dir\": \"${CMAKE_CURRENT_SOURCE_DIR}/include\"
521522
}\"\"\"
522523
${TEMPLATE}
523524
")

src/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ int main(int argc, char** argv) {
718718
const bool must_interpret =
719719
!execute_mode && !compile_mode && !generate_mode && !Global::config().has("swig");
720720
const bool must_execute = execute_mode;
721-
const bool must_compile = must_execute || compile_mode;
721+
const bool must_compile = must_execute || compile_mode || Global::config().has("swig");
722722

723723
try {
724724
if (must_interpret) {

src/souffle-compile.template.py

+115-15
Original file line numberDiff line numberDiff line change
@@ -22,46 +22,146 @@
2222
# "libname_fmt": "-l{}",
2323
# "rpath_fmt": "-Wl,-rpath,{}",
2424
# "path_delimiter": ":",
25-
# "exe_extension": ""
25+
# "exe_extension": "",
26+
# "source_include_dir": ""
2627
#}"""
2728

2829
import argparse
2930
import json
3031
import os
3132
import pathlib
33+
import shutil
3234
import subprocess
3335
import sys
36+
import tempfile
37+
38+
# run command and return status object
39+
def launch_command(cmd, descr, verbose=False):
40+
if verbose:
41+
sys.stdout.write(cmd)
42+
status = subprocess.run(cmd, capture_output=True, text=True, shell=True)
43+
if status.returncode != 0:
44+
sys.stdout.write(status.stdout)
45+
sys.stderr.write(status.stderr)
46+
raise RuntimeError("Error: {}. Command: {}".format(descr, cmd))
47+
return status
48+
49+
# run command and return the standard output as a string
50+
def capture_command_output(cmd, descr, verbose=False):
51+
status = launch_command(cmd, descr, verbose)
52+
return status.stdout
53+
3454

3555
conf = json.loads(JSON_DATA_TEXT)
56+
OUTNAME_FMT = conf['outname_fmt']
57+
LIBDIR_FMT = conf['libdir_fmt']
58+
LIBNAME_FMT = conf['libname_fmt']
59+
RPATH_FMT = conf['rpath_fmt']
60+
PATH_DELIMITER = conf['path_delimiter']
61+
RPATHS = conf['rpaths'].split(PATH_DELIMITER)
62+
exeext = conf['exe_extension']
63+
SOURCE_INCLUDE_DIR = conf['source_include_dir']
64+
65+
workdir = os.getcwd()
66+
scriptdir = pathlib.Path(os.path.dirname(os.path.abspath(__file__)))
3667

37-
parser = argparse.ArgumentParser(description="Compile c++ code generated by Souffle")
68+
parser = argparse.ArgumentParser(description="Compile a C++ source file generated by Souffle")
3869
parser.add_argument('-l', action='append', default=[], metavar='LIBNAME', dest='lib_names', type=str, help="Basename of a functors library. eg: `-l functors` => libfunctors.dll")
3970
parser.add_argument('-L', action='append', default=[], metavar='LIBDIR', dest='lib_dirs', type=lambda p: pathlib.Path(p).absolute(), help="Search directory for functors libraries")
4071
parser.add_argument('-g', action='store_true', dest='debug', help="Debug build type")
41-
parser.add_argument('-s', action='store_true', dest='swig', help="TODO")
42-
parser.add_argument('-v', action='store_true', dest='verbose', help="Verbose")
72+
parser.add_argument('-s', metavar='VALUE', dest='swiglang', help="use SWIG interface to generate into VALUE language")
73+
parser.add_argument('-v', action='store_true', dest='verbose', help="Verbose output")
74+
parser.add_argument('-w', action='store_true', dest='warnings', help="Enable warnings")
75+
parser.add_argument('-t', action='store_true', dest='testmode', help="Build in test mode")
4376
parser.add_argument('source', metavar='SOURCE', type=lambda p: pathlib.Path(p).absolute(), help="C++ source file")
4477

4578
args = parser.parse_args()
4679

80+
stemname = args.source.stem
81+
dirname = args.source.parent
82+
4783
if not os.path.isfile(args.source):
4884
raise RuntimeError("Cannot open source file: '{}'".format(args.source))
4985

86+
# Check if the input file has a valid extension
5087
extname = args.source.suffix
5188
if extname != ".cpp":
5289
raise RuntimeError("Source file is not a .cpp file: '{}'".format(args.source))
5390

54-
basename = args.source.stem
55-
dirname = args.source.parent
56-
exeext = conf['exe_extension']
57-
exepath = pathlib.Path(dirname.joinpath("{}{}".format(basename, exeext)))
58-
59-
OUTNAME_FMT = conf['outname_fmt']
60-
LIBDIR_FMT = conf['libdir_fmt']
61-
LIBNAME_FMT = conf['libname_fmt']
62-
RPATH_FMT = conf['rpath_fmt']
63-
PATH_DELIMITER = conf['path_delimiter']
64-
RPATHS = conf['rpaths'].split(PATH_DELIMITER)
91+
# Search for Souffle includes directory
92+
souffle_include_dir = None
93+
if (scriptdir / "include" / "souffle").exists():
94+
souffle_include_dir = scriptdir / "include" / "souffle"
95+
elif (scriptdir / ".." / "include" / "souffle").exists():
96+
souffle_include_dir = scriptdir / ".." / "include" / "souffle"
97+
elif SOURCE_INCLUDE_DIR and (pathlib.Path(SOURCE_INCLUDE_DIR) / "souffle").exists():
98+
souffle_include_dir = (pathlib.Path(SOURCE_INCLUDE_DIR) / "souffle")
99+
100+
# Make temp folder and copy relevant files there
101+
if args.swiglang:
102+
if not (souffle_include_dir and (souffle_include_dir / "swig").exists()):
103+
raise RuntimeError("Cannot find 'souffle/swig' include directory")
104+
swig_include_dir = (souffle_include_dir / "swig")
105+
with tempfile.TemporaryDirectory() as tmpdir:
106+
shutil.copy(swig_include_dir / "SwigInterface.h", tmpdir)
107+
shutil.copy(swig_include_dir / "SwigInterface.i", tmpdir)
108+
109+
os.chdir(tmpdir)
110+
launch_command("swig -c++ -\"{}\" SwigInterface.i".format(args.swiglang), "SWIG generation")
111+
112+
python_flags = capture_command_output("python3-config --cflags", "Python config")
113+
python_ldflags = capture_command_output("python3-config --ldflags", "Python config")
114+
115+
if args.swiglang == "python":
116+
# compile swig interface and program
117+
cmd = []
118+
cmd.append('"{}"'.format(conf['compiler']))
119+
cmd.append("-fPIC")
120+
cmd.append("-c")
121+
cmd.append("-D__EMBEDDED_SOUFFLE__")
122+
cmd.append("SwigInterface_wrap.cxx")
123+
cmd.append(str(args.source))
124+
cmd.append(conf['definitions'])
125+
cmd.append(conf['compile_options'])
126+
cmd.append(conf['includes'])
127+
cmd.append(conf['std_flag'])
128+
cmd.append(conf['cxx_flags'])
129+
cmd.append(python_flags)
130+
cmd = " ".join(cmd)
131+
launch_command(cmd, "Compilation of SWIG python C++")
132+
133+
# link swig interface and program
134+
cmd = []
135+
cmd.append('"{}"'.format(conf['compiler']))
136+
cmd.append("-shared")
137+
cmd.append("SwigInterface_wrap.o")
138+
cmd.append("{}{}".format(stemname, ".o"))
139+
cmd.append("-o")
140+
cmd.append("_SwigInterface.so")
141+
cmd.append(conf['definitions'])
142+
cmd.append(conf['compile_options'])
143+
cmd.append(conf['includes'])
144+
cmd.append(conf['std_flag'])
145+
cmd.append(conf['cxx_flags'])
146+
cmd.append(conf['link_options'])
147+
cmd.extend(list(map(lambda rpath: RPATH_FMT.format(rpath), RPATHS)))
148+
cmd.extend(list(map(lambda libdir: LIBDIR_FMT.format(libdir), args.lib_dirs)))
149+
cmd.extend(list(map(lambda libname: LIBNAME_FMT.format(libname), args.lib_names)))
150+
cmd.append(python_ldflags)
151+
cmd = " ".join(cmd)
152+
launch_command(cmd, "Link of SWIG python C++")
153+
154+
shutil.copy("_SwigInterface.so", workdir)
155+
shutil.copy("SwigInterface.py", workdir)
156+
157+
elif args.swiglang == "java":
158+
raise RuntimeError("TODO: Swig Java")
159+
160+
# move generated files to same directory as cpp file
161+
os.sys.exit(0)
162+
163+
164+
exepath = pathlib.Path(dirname.joinpath("{}{}".format(stemname, exeext)))
65165

66166
cmd = []
67167
cmd.append('"{}"'.format(conf['compiler']))

tests/swig/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function(SOUFFLE_RUN_PYTHON_SWIG_TEST)
1616
)
1717

1818
add_test(NAME ${PARAM_QUALIFIED_TEST_NAME}_run_swig
19-
COMMAND sh -c "set -e; PYTHONPATH=. '${Python3_EXECUTABLE}' '${PARAM_INPUT_DIR}/driver.py' '${PARAM_FACTS_DIR}'
19+
COMMAND sh -c "set -e; PYTHONPATH=. '${Python3_EXECUTABLE}' '${PARAM_INPUT_DIR}/driver.py' '${PARAM_FACTS_DIR}' \\
2020
1> '${PARAM_TEST_NAME}-python.out' \\
2121
2> '${PARAM_TEST_NAME}-python.err'")
2222
set_tests_properties(${PARAM_QUALIFIED_TEST_NAME}_run_swig PROPERTIES

tests/swig/python/family/family-python.out

Whitespace-only changes.

0 commit comments

Comments
 (0)