diff --git a/.github/images/arch-linux/PKGBUILD.in b/.github/images/arch-linux/PKGBUILD.in
index ee7f388d5a4..820ec37ed54 100644
--- a/.github/images/arch-linux/PKGBUILD.in
+++ b/.github/images/arch-linux/PKGBUILD.in
@@ -16,8 +16,8 @@ arch=('any')
url="https://github.com/souffle-lang/souffle"
license=('UPL')
groups=()
-depends=('mcpp' 'gcc>=8' 'openmp' 'sqlite')
-makedepends=('git' 'cmake>=3.15' 'bison>=3.0.4' 'flex' 'libffi' 'ncurses' 'zlib')
+depends=('mcpp' 'gcc>=8' 'openmp' 'sqlite' 'python3')
+makedepends=('git' 'cmake>=3.15' 'bison>=3.0.4' 'flex' 'libffi' 'ncurses' 'zlib' 'python3')
optdepends=('bash-completion')
provides=('souffle')
conflicts=('souffle-git')
diff --git a/.github/workflows/VS-CI-Tests.yml b/.github/workflows/VS-CI-Tests.yml
new file mode 100644
index 00000000000..1f06de3ea11
--- /dev/null
+++ b/.github/workflows/VS-CI-Tests.yml
@@ -0,0 +1,76 @@
+name: VS-CI-Tests
+
+on:
+ # TODO remove me before merge
+ push:
+ branches:
+ - '**'
+ pull_request:
+ types: [opened, synchronize]
+ workflow_dispatch:
+
+env:
+ CHOCO_CACHE_DIR: "${{ github.workspace }}/choco-cache"
+
+jobs:
+
+ Windows-CMake-MSVC:
+ runs-on: windows-2019
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Dependencies Cache
+ uses: actions/cache@v2
+ env:
+ cache-name: cache-chocolatey
+ with:
+ # cache Chocolatey packages to speed-up the deployment.
+ path: |
+ ${{ env.CHOCO_CACHE_DIR }}
+ key: windows-${{ hashFiles('choco-packages.config') }}
+
+ # Use Chocolatey to install binary dependencies.
+ - name: Binary Dependencies (Chocolatey)
+ run: |
+ choco config set cacheLocation ${{ env.CHOCO_CACHE_DIR }}
+ choco install choco-packages.config --no-progress --installargs 'ADD_CMAKE_TO_PATH=""System""'
+
+ # Use vcpkg to install devel library dependencies.
+ - name: Library Dependencies (vcpkg)
+ uses: lukka/run-vcpkg@v7
+ with:
+ vcpkgGitCommitId: '3a28333d605f92f8659f3af1137324b2d9886101'
+ vcpkgTriplet: x64-windows
+ vcpkgArguments: 'sqlite3 zlib libffi'
+
+ - name: Create Build Directory
+ working-directory: ${{github.workspace}}
+ run: mkdir build
+
+ - name: Configure Build
+ working-directory: ${{github.workspace}}
+ run: |
+ $env:ChocolateyInstall = Convert-Path "$((Get-Command choco).Path)\..\.."
+ Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
+ refreshenv
+ cmake -S . -B build -G "Visual Studio 16 2019" -A x64 "-DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake" -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=/bigobj -DSOUFFLE_DOMAIN_64BIT=ON -DCMAKE_FIND_LIBRARY_PREFIXES=";lib" -DCMAKE_FIND_LIBRARY_SUFFIXES=".lib;.dll" -DSOUFFLE_USE_CURSES=OFF -DSOUFFLE_USE_ZLIB=ON -DCMAKE_FIND_DEBUG_MODE=FALSE -DSOUFFLE_BASH_COMPLETION=OFF
+
+ - name: Build
+ working-directory: ${{github.workspace}}
+ run: cmake --build build --config Release -j4
+
+ # Run the tests, Visual Studio must be in the environment because cl.exe is required for compiled Souffle.
+ - name: Check interpreter
+ working-directory: ${{github.workspace}}/build
+ shell: cmd
+ run: |
+ pushd "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build" & call vcvars64.bat & popd
+ ctest --output-on-failure --build-config Release --progress -j4 -L interpreted
+
+ - name: Check others
+ working-directory: ${{github.workspace}}/build
+ shell: cmd
+ run: |
+ pushd "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build" & call vcvars64.bat & popd
+ ctest --output-on-failure --build-config Release --progress -j2 -LE interpreted
+
diff --git a/.github/workflows/cancel.yml b/.github/workflows/cancel.yml
index 8912bf20d1a..d4fa2ba9d00 100644
--- a/.github/workflows/cancel.yml
+++ b/.github/workflows/cancel.yml
@@ -1,7 +1,7 @@
name: Cancel
on:
workflow_run:
- workflows: ["CI-Tests"]
+ workflows: ["CI-Tests", "VS-CI-Tests"]
types:
- requested
jobs:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9cdaa22e2fd..b02978ef337 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -99,6 +99,7 @@ option(SOUFFLE_GENERATE_DOXYGEN "Generate Doxygen files (html;htmlhelp;man;rtf;x
option(SOUFFLE_CODE_COVERAGE "Enable coverage reporting" OFF)
option(SOUFFLE_BASH_COMPLETION "Enable/Disable bash completion" OFF)
option(SOUFFLE_USE_LIBFFI "Enable/Disable use of libffi" ON)
+option(SOUFFLE_CUSTOM_GETOPTLONG "Enable/Disable custom getopt_long implementation" OFF)
cmake_dependent_option(SOUFFLE_USE_LIBCPP "Link to libc++ instead of libstdc++" ON
"CMAKE_CXX_COMPILER_ID STREQUAL Clang" OFF)
@@ -120,6 +121,24 @@ if (SOUFFLE_USE_LIBCPP)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -lc++abi")
endif()
+if (WIN32)
+ # Search libraries with and without 'lib' prefix.
+ set(CMAKE_FIND_LIBRARY_PREFIXES ";lib")
+
+ # Prefix all shared libraries with 'lib'.
+ set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
+
+ # Prefix all static libraries with 'lib'.
+ set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+
+ SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${OUTPUT_DIRECTORY}")
+ SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${OUTPUT_DIRECTORY}")
+ SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${OUTPUT_DIRECTORY}")
+ SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${OUTPUT_DIRECTORY}")
+ SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${OUTPUT_DIRECTORY}")
+ SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${OUTPUT_DIRECTORY}")
+endif ()
+
# --------------------------------------------------
# curses libraries for Provenance information
# --------------------------------------------------
@@ -147,7 +166,7 @@ if (SOUFFLE_SWIG_PYTHON OR SOUFFLE_SWIG_JAVA)
find_package(SWIG REQUIRED)
if (SOUFFLE_SWIG_PYTHON)
- find_package(Python "3.7" REQUIRED)
+ find_package(Python3 3.7 REQUIRED)
endif()
if (SOUFFLE_SWIG_JAVA)
@@ -218,7 +237,10 @@ endif()
# libffi
# --------------------------------------------------
if (SOUFFLE_USE_LIBFFI)
- find_package(LibFFI REQUIRED)
+ find_package(libffi CONFIG QUIET)
+ if (NOT libffi_FOUND)
+ find_package(LibFFI REQUIRED)
+ endif()
endif()
# --------------------------------------------------
@@ -232,11 +254,6 @@ find_package(Threads REQUIRED)
# --------------------------------------------------
if (SOUFFLE_USE_OPENMP)
find_package(OpenMP)
- if (OPENMP_FOUND)
- set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
- set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
- set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
- endif()
endif()
# --------------------------------------------------
@@ -338,6 +355,7 @@ endif(SOUFFLE_CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_subdirectory(src)
if (SOUFFLE_ENABLE_TESTING)
+ find_package(Python3 3.7 REQUIRED)
add_subdirectory(src/tests)
add_subdirectory(tests)
endif()
@@ -367,6 +385,7 @@ IF (SOUFFLE_BASH_COMPLETION)
endif()
+if (NOT WIN32)
# --------------------------------------------------
# CPack configuration
# --------------------------------------------------
@@ -396,7 +415,7 @@ if (CHECK_OS_RESULT EQUAL 0)
# --------------------------------------------------
# Specifying runtime dependencies
- set(CPACK_DEBIAN_PACKAGE_DEPENDS "g++ (>= 8), libffi-dev, libncurses5-dev, libsqlite3-dev, mcpp, zlib1g-dev")
+ set(CPACK_DEBIAN_PACKAGE_DEPENDS "g++ (>= 8), libffi-dev, libncurses5-dev, libsqlite3-dev, mcpp, zlib1g-dev, python3")
# Auto-generate any runtime dependencies that are required
SET(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
@@ -407,22 +426,23 @@ if (CHECK_OS_RESULT EQUAL 0)
endif()
if (CHECK_OS_OUTPUT MATCHES "FEDORA" OR CHECK_OS_OUTPUT MATCHES "CENTOS")
- SET(CPACK_RPM_PACKAGE_GROUP "Unspecified")
- SET(CPACK_RPM_PACKAGE_LICENSE "UPL-1.0 License")
- SET(CPACK_RPM_PACKAGE_VENDOR "Souffle-lang")
+ SET(CPACK_RPM_PACKAGE_GROUP "Unspecified")
+ SET(CPACK_RPM_PACKAGE_LICENSE "UPL-1.0 License")
+ SET(CPACK_RPM_PACKAGE_VENDOR "Souffle-lang")
- # Generate both DEB and RPM packages
- SET(CPACK_GENERATOR "RPM")
+ # Generate both DEB and RPM packages
+ SET(CPACK_GENERATOR "RPM")
- # --------------------------------------------------
- # Variables relevent to RPM packages
- # --------------------------------------------------
+ # --------------------------------------------------
+ # Variables relevent to RPM packages
+ # --------------------------------------------------
- # Specifying runtime dependencies
- set(CPACK_RPM_PACKAGE_REQUIRES "gcc-c++ >= 8, libffi, libffi-devel, ncurses-devel, sqlite-devel, mcpp, zlib-devel")
+ # Specifying runtime dependencies
+ set(CPACK_RPM_PACKAGE_REQUIRES "gcc-c++ >= 8, libffi, libffi-devel, ncurses-devel, sqlite-devel, mcpp, zlib-devel, python3")
- # Note: By default automatic dependency detection is enabled by rpm generator.
- # SET(CPACK_RPM_PACKAGE_AUTOREQPROV "no")
- INCLUDE(CPack)
- endif()
+ # Note: By default automatic dependency detection is enabled by rpm generator.
+ # SET(CPACK_RPM_PACKAGE_AUTOREQPROV "no")
+ INCLUDE(CPack)
+ endif()
+endif()
endif()
diff --git a/README.md b/README.md
index 6d0340b8783..aca3a690f69 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@ domain-specific language for analysis problems.
[![License: UPL](https://img.shields.io/badge/License-UPL--1.0-blue.svg)](https://github.com/souffle-lang/souffle/blob/master/LICENSE)
[![CI-Tests](https://github.com/souffle-lang/souffle/actions/workflows/CI-Tests.yml/badge.svg)](https://github.com/souffle-lang/souffle/actions/workflows/CI-Tests.yml)
+[![MSVC-CI-Tests](https://github.com/souffle-lang/souffle/actions/workflows/VS-CI-Tests.yml/badge.svg)](https://github.com/souffle-lang/souffle/actions/workflows/VS-CI-Tests.yml)
[![codecov](https://codecov.io/gh/souffle-lang/souffle/branch/master/graph/badge.svg)](https://codecov.io/gh/souffle-lang/souffle)
## Features of Soufflé
diff --git a/choco-packages.config b/choco-packages.config
new file mode 100644
index 00000000000..aebe6bf4350
--- /dev/null
+++ b/choco-packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/cmake/SouffleTests.cmake b/cmake/SouffleTests.cmake
index d20cde4ff3f..983a209092f 100644
--- a/cmake/SouffleTests.cmake
+++ b/cmake/SouffleTests.cmake
@@ -13,14 +13,18 @@ function(SOUFFLE_SETUP_INTEGRATION_TEST_DIR)
${ARGV}
)
-if ("provenance" IN_LIST TEST_LABELS)
- set (PARAM_EXTRA_DATA "provenance")
- endif()
+ if ("provenance" IN_LIST TEST_LABELS)
+ set (PARAM_EXTRA_DATA "provenance")
+ endif()
- # Set up the test directory
+#Set up the test directory
add_test(NAME ${PARAM_QUALIFIED_TEST_NAME}_setup
- COMMAND "${PROJECT_SOURCE_DIR}/cmake/setup_test_dir.sh" "${PARAM_DATA_CHECK_DIR}" "${PARAM_OUTPUT_DIR}"
- "${PARAM_TEST_NAME}" "${PARAM_EXTRA_DATA}")
+ COMMAND ${Python3_EXECUTABLE} "${PROJECT_SOURCE_DIR}/cmake/setup_test_dir.py"
+ "${PARAM_DATA_CHECK_DIR}"
+ "${PARAM_OUTPUT_DIR}"
+ "${PARAM_TEST_NAME}"
+ "${PARAM_EXTRA_DATA}")
+
set_tests_properties(${PARAM_QUALIFIED_TEST_NAME}_setup PROPERTIES
LABELS "${PARAM_TEST_LABELS}"
FIXTURES_SETUP ${PARAM_FIXTURE_NAME}_setup)
@@ -31,34 +35,37 @@ function(SOUFFLE_RUN_INTEGRATION_TEST)
cmake_parse_arguments(
PARAM
""
- "TEST_NAME;QUALIFIED_TEST_NAME;INPUT_DIR;OUTPUT_DIR;FIXTURE_NAME;SOUFFLE_PARAMS;NEGATIVE"
- "TEST_LABELS"
+ "TEST_NAME;QUALIFIED_TEST_NAME;INPUT_DIR;OUTPUT_DIR;FIXTURE_NAME;NEGATIVE"
+ "TEST_LABELS;SOUFFLE_PARAMS"
${ARGV}
)
- # Run souffle (through the shell, so we can easily redirect)
- set(SOUFFLE_CMD "set -e$ '$' ${PARAM_SOUFFLE_PARAMS} '${PARAM_INPUT_DIR}/${PARAM_TEST_NAME}.dl'\\
- 1> '${PARAM_TEST_NAME}.out'\\
- 2> '${PARAM_TEST_NAME}.err'")
-
if ("provenance" IN_LIST TEST_LABELS)
- set (SOUFFLE_CMD "${SOUFFLE_CMD} < '${PARAM_TEST_NAME}.in'")
+ set (STDIN_ARGS "--in" "${PARAM_TEST_NAME}.in")
endif()
add_test(NAME ${PARAM_QUALIFIED_TEST_NAME}_run_souffle
- COMMAND sh -c "${SOUFFLE_CMD}")
+ COMMAND
+ ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/cmake/redirect.py
+ --out ${PARAM_TEST_NAME}.out
+ --err ${PARAM_TEST_NAME}.err
+ ${STDIN_ARGS}
+ $
+ ${PARAM_SOUFFLE_PARAMS}
+ "${PARAM_INPUT_DIR}/${PARAM_TEST_NAME}.dl"
+ COMMAND_EXPAND_LISTS)
set_tests_properties(${PARAM_QUALIFIED_TEST_NAME}_run_souffle PROPERTIES
- # Switch to output dir so that any "extra" files generated by
- # souffle are dropped in there
- WORKING_DIRECTORY "${PARAM_OUTPUT_DIR}"
- LABELS "${PARAM_TEST_LABELS}"
- FIXTURES_SETUP ${PARAM_FIXTURE_NAME}_run_souffle
- FIXTURES_REQUIRED ${PARAM_FIXTURE_NAME}_setup)
+ #Switch to output dir so that any "extra" files generated by
+ #souffle are dropped in there
+ WORKING_DIRECTORY "${PARAM_OUTPUT_DIR}"
+ LABELS "${PARAM_TEST_LABELS}"
+ FIXTURES_SETUP ${PARAM_FIXTURE_NAME}_run_souffle
+ FIXTURES_REQUIRED ${PARAM_FIXTURE_NAME}_setup)
if (PARAM_NEGATIVE)
- # Mark the souffle run as "will fail" for negative tests
- set_tests_properties(${PARAM_QUALIFIED_TEST_NAME}_run_souffle PROPERTIES WILL_FAIL TRUE)
+ #Mark the souffle run as "will fail" for negative tests
+ set_tests_properties(${PARAM_QUALIFIED_TEST_NAME}_run_souffle PROPERTIES WILL_FAIL TRUE)
endif()
endfunction()
@@ -73,7 +80,11 @@ function(SOUFFLE_COMPARE_STD_OUTPUTS)
)
add_test(NAME ${PARAM_QUALIFIED_TEST_NAME}_compare_std_outputs
- COMMAND "${PROJECT_SOURCE_DIR}/cmake/check_std_outputs.sh" "${PARAM_TEST_NAME}" "${PARAM_EXTRA_DATA}")
+ COMMAND
+ ${Python3_EXECUTABLE} "${PROJECT_SOURCE_DIR}/cmake/check_std_outputs.py"
+ "${PARAM_TEST_NAME}"
+ "${PARAM_EXTRA_DATA}")
+
set_tests_properties(${PARAM_QUALIFIED_TEST_NAME}_compare_std_outputs PROPERTIES
WORKING_DIRECTORY "${PARAM_OUTPUT_DIR}"
LABELS "${PARAM_TEST_LABELS}"
@@ -90,7 +101,7 @@ function(SOUFFLE_COMPARE_CSV)
)
if (NOT PARAM_NEGATIVE)
- # If there are "extra outputs", handle them
+#If there are "extra outputs", handle them
if (PARAM_EXTRA_DATA)
if (PARAM_EXTRA_DATA STREQUAL "gzip")
set(EXTRA_BINARY "${GZIP_BINARY}")
@@ -104,29 +115,31 @@ function(SOUFFLE_COMPARE_CSV)
endif()
add_test(NAME ${QUALIFIED_TEST_NAME}_compare_csv
- COMMAND "${PROJECT_SOURCE_DIR}/cmake/check_test_results.sh"
- "${PARAM_INPUT_DIR}" ${PARAM_EXTRA_DATA} "${EXTRA_BINARY}")
+ COMMAND ${Python3_EXECUTABLE} "${PROJECT_SOURCE_DIR}/cmake/check_test_results.py"
+ "${PARAM_INPUT_DIR}"
+ ${PARAM_EXTRA_DATA}
+ "${EXTRA_BINARY}")
set_tests_properties(${QUALIFIED_TEST_NAME}_compare_csv PROPERTIES
- WORKING_DIRECTORY "${PARAM_OUTPUT_DIR}"
- LABELS "${PARAM_TEST_LABELS}"
- FIXTURES_REQUIRED ${PARAM_RUN_AFTER_FIXTURE})
+ WORKING_DIRECTORY "${PARAM_OUTPUT_DIR}"
+ LABELS "${PARAM_TEST_LABELS}"
+ FIXTURES_REQUIRED ${PARAM_RUN_AFTER_FIXTURE})
endif()
endfunction()
function(SOUFFLE_RUN_TEST_HELPER)
- # PARAM_CATEGORY - e.g. syntactic, example etc.
- # PARAM_TEST_NAME - the name of the test, the short directory name under tests//
- # PARAM_COMPILED - with or without -c
- # PARAM_FUNCTORS - with -L for finding functor library in the testsuite
- # PARAM_NEGATIVE - should it fail or not
- # PARAM_MULTI_TEST - used to distinguish "multi-tests", sort of left over from automake
- # Basically, the same test dir has multiple sets of facts/outputs
- # We should just get rid of this and make multiple tests
- # It also means we need to use slightly different naming for tests
- # and input paths
- # PARAM_FACTS_DIR_NAME - the name of the "facts" subdirectory in each test.
- # Usually just "facts" but can be different when running multi-tests
+#PARAM_CATEGORY - e.g.syntactic, example etc.
+#PARAM_TEST_NAME - the name of the test, the short directory name under tests / /
+#PARAM_COMPILED - with or without -c
+#PARAM_FUNCTORS - with -L for finding functor library in the testsuite
+#PARAM_NEGATIVE - should it fail or not
+#PARAM_MULTI_TEST - used to distinguish "multi-tests", sort of left over from automake
+#Basically, the same test dir has multiple sets of facts / outputs
+#We should just get rid of this and make multiple tests
+#It also means we need to use slightly different naming for tests
+#and input paths
+#PARAM_FACTS_DIR_NAME - the name of the "facts" subdirectory in each test.
+#Usually just "facts" but can be different when running multi - tests
cmake_parse_arguments(
PARAM
"COMPILED;FUNCTORS;NEGATIVE;MULTI_TEST" # Options
@@ -135,8 +148,10 @@ function(SOUFFLE_RUN_TEST_HELPER)
${ARGV}
)
+ set(EXTRA_FLAGS)
+
if (PARAM_COMPILED)
- set(EXTRA_FLAGS "-c")
+ list(APPEND EXTRA_FLAGS "-c")
set(EXEC_STYLE "compiled")
set(SHORT_EXEC_STYLE "_c")
else()
@@ -144,8 +159,16 @@ function(SOUFFLE_RUN_TEST_HELPER)
set(SHORT_EXEC_STYLE "")
endif()
+ if (MSVC)
+ list(APPEND EXTRA_FLAGS "--preprocessor" "cl -nologo -TC -E")
+ endif()
+
if (PARAM_FUNCTORS)
- set(EXTRA_FLAGS "${EXTRA_FLAGS} '-L${CMAKE_CURRENT_BINARY_DIR}/${PARAM_TEST_NAME}'")
+ #if (MSVC)
+ # list(APPEND EXTRA_FLAGS "-L${CMAKE_CURRENT_BINARY_DIR}/${PARAM_TEST_NAME}/${CMAKE_BUILD_TYPE}")
+ #else ()
+ list(APPEND EXTRA_FLAGS "-L${CMAKE_CURRENT_BINARY_DIR}/${PARAM_TEST_NAME}")
+ #endif ()
endif()
if (NOT PARAM_FACTS_DIR_NAME)
@@ -164,8 +187,8 @@ function(SOUFFLE_RUN_TEST_HELPER)
endif()
set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${PARAM_TEST_NAME}${MT_EXTRA_SUFFIX}_${EXEC_STYLE}")
- # Give the test a name which has good info about it when running
- # People can then search for the test by the name, or the labels we create
+#Give the test a name which has good info about it when running
+#People can then search for the test by the name, or the labels we create
set(QUALIFIED_TEST_NAME ${PARAM_CATEGORY}/${PARAM_TEST_NAME}${MT_EXTRA_SUFFIX}${SHORT_EXEC_STYLE})
set(FIXTURE_NAME ${QUALIFIED_TEST_NAME}_fixture)
@@ -175,7 +198,7 @@ function(SOUFFLE_RUN_TEST_HELPER)
set(POS_LABEL "positive")
endif()
- # Label the tests as e.g. "semantic", compiled/interpreted, positive/negative, and integration
+#Label the tests as e.g."semantic", compiled / interpreted, positive / negative, and integration
set(TEST_LABELS "${PARAM_CATEGORY};${EXEC_STYLE};${POS_LABEL};integration")
souffle_setup_integration_test_dir(TEST_NAME ${PARAM_TEST_NAME}
@@ -186,10 +209,11 @@ function(SOUFFLE_RUN_TEST_HELPER)
FIXTURE_NAME ${FIXTURE_NAME}
TEST_LABELS ${TEST_LABELS})
+ set(SOUFFLE_PARAMS "-D" "." "-F" "${FACTS_DIR}")
+ list(PREPEND SOUFFLE_PARAMS ${EXTRA_FLAGS})
+
if (OPENMP_FOUND)
- set(SOUFFLE_PARAMS "${EXTRA_FLAGS} -j8 -D . -F '${FACTS_DIR}'")
- else()
- set(SOUFFLE_PARAMS "${EXTRA_FLAGS} -D . -F '${FACTS_DIR}'")
+ list(APPEND SOUFFLE_PARAMS "-j8")
endif()
souffle_run_integration_test(TEST_NAME ${PARAM_TEST_NAME}
@@ -242,21 +266,32 @@ function(SOUFFLE_ADD_BINARY_TEST TEST_NAME CATEGORY)
set(TARGET_NAME "test_${SHORT_TEST_NAME}")
add_executable(${TARGET_NAME} ${TEST_NAME}.cpp)
+ set(CMAKE_CXX_STANDARD 17)
if (PARAM_SOUFFLE_HEADERS_ONLY)
get_target_property(SOUFFLE_COMPILE_EXTS libsouffle CXX_EXTENSIONS)
get_target_property(SOUFFLE_COMPILE_DEFS libsouffle INTERFACE_COMPILE_DEFINITIONS)
get_target_property(SOUFFLE_COMPILE_FEAT libsouffle INTERFACE_COMPILE_FEATURES)
- get_target_property(SOUFFLE_COMPILE_OPTS libsouffle INTERFACE_COMPILE_OPTIONS)
+ get_target_property(SOUFFLE_COMPILE_OPTS libsouffle COMPILE_OPTIONS)
get_target_property(SOUFFLE_INCLUDE_DIRS libsouffle INTERFACE_INCLUDE_DIRECTORIES)
+ if (OPENMP_FOUND)
+ target_link_libraries(${TARGET_NAME} PRIVATE OpenMP::OpenMP_CXX)
+ endif()
+
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
+ target_link_libraries(${TARGET_NAME} PRIVATE stdc++fs)
+ endif ()
+ endif()
+
set_target_properties(${TARGET_NAME} PROPERTIES CXX_EXTENSIONS SOUFFLE_COMPILE_EXTS)
target_compile_definitions(${TARGET_NAME} PRIVATE ${SOUFFLE_COMPILE_DEFS})
target_compile_features(${TARGET_NAME} PRIVATE ${SOUFFLE_COMPILE_FEAT})
target_compile_options(${TARGET_NAME} PRIVATE ${SOUFFLE_COMPILE_OPTS})
target_include_directories(${TARGET_NAME} PRIVATE ${SOUFFLE_INCLUDE_DIRS})
else()
- target_link_libraries(${TARGET_NAME} libsouffle)
+ target_link_libraries(${TARGET_NAME} libsouffle)
endif()
set(QUALIFIED_TEST_NAME ${SHORT_TEST_NAME})
diff --git a/cmake/check_std_outputs.py b/cmake/check_std_outputs.py
new file mode 100644
index 00000000000..219926199ce
--- /dev/null
+++ b/cmake/check_std_outputs.py
@@ -0,0 +1,35 @@
+# Souffle - A Datalog Compiler
+# Copyright (c) 2022 The Souffle Developers. All rights reserved
+# Licensed under the Universal Permissive License v 1.0 as shown at:
+# - https://opensource.org/licenses/UPL
+# - /licenses/SOUFFLE-UPL.txt
+
+import os
+from common import *
+
+args = os.sys.argv
+args.pop(0)
+
+if len(args) == 0:
+ raise RuntimeError("Missing TEST_NAME")
+
+test_name = args.pop(0)
+
+if len(args) > 0:
+ extra_data = args.pop(0)
+else:
+ extra_data = None
+
+if len(args) != 0:
+ raise RuntimeError("Unexpected argument")
+
+sort_file("{}.out".format(test_name))
+compare_sorted_file("{}.out".format(test_name))
+
+compare_file("{}.err".format(test_name))
+
+if extra_data == "python" or extra_data == "java":
+ file_name = "{}-{}.out".format(test_name, extra_data)
+ sort_file(file_name)
+ compare_sorted_file(file_name)
+
diff --git a/cmake/check_std_outputs.sh b/cmake/check_std_outputs.sh
deleted file mode 100755
index d03e4534ce6..00000000000
--- a/cmake/check_std_outputs.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-# Souffle - A Datalog Compiler
-# Copyright (c) 2021 The Souffle Developers. All rights reserved
-# Licensed under the Universal Permissive License v 1.0 as shown at:
-# - https://opensource.org/licenses/UPL
-# - /licenses/SOUFFLE-UPL.txt
-
-set -e
-
-TEST_NAME="$1"
-EXTRA_DATA="$2"
-
-if [ -z ${EXTRA_DATA} ]; then
- EXTRA_DATA="nothing"
-fi
-
-if [ ${EXTRA_DATA} = "json" ]; then
- # The json tests require additional shenanigans
- sed 's/\(@<:@@:>@,@:>@\)$/\\1/' "${TEST_NAME}.out" | sort > "${TEST_NAME}.out.sorted"
-else
- sort "${TEST_NAME}.out" > "${TEST_NAME}.out.sorted"
-fi;
-
-diff "${TEST_NAME}.out.sorted" "${TEST_NAME}.out.expected.sorted"
-
-diff "${TEST_NAME}.err" "${TEST_NAME}.err.expected"
-
-if [ ${EXTRA_DATA} = "python" ] || [ ${EXTRA_DATA} = "java" ]; then
- # We also want to check the output from the swig run
- sort "${TEST_NAME}-${EXTRA_DATA}.out" > "${TEST_NAME}-${EXTRA_DATA}.out.sorted"
- diff "${TEST_NAME}-${EXTRA_DATA}.out.sorted" "${TEST_NAME}-${EXTRA_DATA}.out.expected.sorted"
-fi
diff --git a/cmake/check_test_results.py b/cmake/check_test_results.py
new file mode 100644
index 00000000000..20ccd4f8a32
--- /dev/null
+++ b/cmake/check_test_results.py
@@ -0,0 +1,83 @@
+# Souffle - A Datalog Compiler
+# Copyright (c) 2022 The Souffle Developers. All rights reserved
+# Licensed under the Universal Permissive License v 1.0 as shown at:
+# - https://opensource.org/licenses/UPL
+# - /licenses/SOUFFLE-UPL.txt
+
+import os
+import glob
+import subprocess
+from common import *
+
+args = os.sys.argv
+args.pop(0)
+
+if len(args) == 0:
+ raise RuntimeError("Missing INPUT_DIR")
+
+input_dir = args.pop(0)
+extra_data = None
+binary = None
+
+if len(args) > 0:
+ arg = args.pop(0)
+ if arg == "":
+ extra_data = None
+ elif arg == "sqlite3" or arg == "gzip":
+ extra_data = arg
+ if len(args) == 0:
+ raise RuntimeError("Missing BINARY")
+ binary = args.pop(0)
+ elif arg == "json":
+ extra_data = arg
+ if len(args) > 0:
+ args.pop(0) # unused last argument
+ else:
+ raise RuntimeError("Unknown processing type {}".format(arg))
+
+if len(args) != 0:
+ raise RuntimeError("Unexpected argument")
+
+if extra_data == "gzip":
+ extra_file_pattern = "*.gz.output"
+elif extra_data == "sqlite3":
+ extra_file_pattern = "*.sqlite.output"
+elif extra_data == "json":
+ extra_file_pattern = "*.json"
+else:
+ extra_file_pattern = None
+
+if extra_file_pattern:
+ extra_files = glob.glob(extra_file_pattern)
+
+ for file in extra_files:
+ if extra_data == "gzip":
+ generated_file = os.path.basename(file).rstrip(".gz.output")
+ with open(generated_file, "w") as generated:
+ subprocess.run([binary, "-d", "-c", file], check=True, stdout=generated)
+ elif extra_data == "sqlite3":
+ generated_file = "{}.csv".format(os.path.basename(file).rstrip(".sqlite.output"))
+ script = os.path.join(input_dir, "{}.script".format(file))
+ with open(generated_file, "w") as generated:
+ subprocess.run([binary,"-batch","-init",script,file,""], check=True, stdout=generated)
+ elif extra_data == "json":
+ generated_file = file
+
+ sort_file(generated_file)
+ compare_sorted_file(generated_file)
+
+generated_csvs = glob.glob("*.csv")
+
+with open("num.generated", "w") as num_file:
+ num_file.write("{}\n".format(len(generated_csvs)))
+
+compare_files("num.expected", "num.generated")
+
+csvs = list(map(
+ lambda file: os.path.basename(file).rstrip(".expected.sorted"),
+ glob.glob("*.csv.expected.sorted")))
+
+for csv_file in csvs:
+ sort_file(csv_file)
+ compare_sorted_file(csv_file)
+
diff --git a/cmake/check_test_results.sh b/cmake/check_test_results.sh
deleted file mode 100755
index 470a6f5b83a..00000000000
--- a/cmake/check_test_results.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-# Souffle - A Datalog Compiler
-# Copyright (c) 2021 The Souffle Developers. All rights reserved
-# Licensed under the Universal Permissive License v 1.0 as shown at:
-# - https://opensource.org/licenses/UPL
-# - /licenses/SOUFFLE-UPL.txt
-
-set -e
-
-INPUT_DIR="$1"
-EXTRA_DATA="$2"
-BINARY="$3" #BINARY will be set to gzip or sqlite3
-
-find . -maxdepth 1 -name "*.csv.expected.sorted" | wc -l > num.generated
-
-diff num.generated num.expected
-
-for file in $(find . -maxdepth 1 -name "*.csv"); do
- sort "${file}" > "${file}.generated.sorted"
- diff "${file}.generated.sorted" "${file}.expected.sorted"
-done
-
-
-if [ -z ${EXTRA_DATA} ]; then
- # We're done
- exit 0
-elif [ ${EXTRA_DATA} = "gzip" ]; then
- EXTRA_FILE_PAT="*.output"
-elif [ ${EXTRA_DATA} = "sqlite3" ]; then
- EXTRA_FILE_PAT="*.output"
-elif [ ${EXTRA_DATA} = "json" ]; then
- EXTRA_FILE_PAT="*.json"
-else
- echo "Unknown processing type '${EXTRA_DATA}'"
- exit 1
-fi
-
-EXTRA_FILES=$(find . -maxdepth 1 -name "${EXTRA_FILE_PAT}")
-
-for file in ${EXTRA_FILES}; do
- if [ ${EXTRA_DATA} = "gzip" ]; then
- # Strip the .gz.output suffix. There should be a corresponding .csv file
- # in the input directory
- EXTRA_FILE=${file%%.gz.output}
- "${BINARY}" -d -c "$file" > "${EXTRA_FILE}.generated.unsorted"
- elif [ ${EXTRA_DATA} = "sqlite3" ]; then
- # Strip the .sqlite.output suffix. There should be a corresponding .csv file
- # in the input directory
- EXTRA_FILE=${file%%.sqlite.output}.csv
- "${BINARY}" -batch "$file" -init "${INPUT_DIR}/$file.script" "" > "${EXTRA_FILE}.generated.unsorted"
- elif [ ${EXTRA_DATA} = "json" ]; then
- EXTRA_FILE="${file}"
- sed 's/\(@<:@@:>@,@:>@\)$/\\1/' "${file}" > "${file}.generated.unsorted"
- fi
-
- sort "${EXTRA_FILE}.generated.unsorted" > "${EXTRA_FILE}.generated.sorted"
- diff "${EXTRA_FILE}.generated.sorted" "${EXTRA_FILE}.expected.sorted"
-done
diff --git a/cmake/common.py b/cmake/common.py
new file mode 100644
index 00000000000..9e999d04c68
--- /dev/null
+++ b/cmake/common.py
@@ -0,0 +1,65 @@
+# Souffle - A Datalog Compiler
+# Copyright (c) 2022 The Souffle Developers. All rights reserved
+# Licensed under the Universal Permissive License v 1.0 as shown at:
+# - https://opensource.org/licenses/UPL
+# - /licenses/SOUFFLE-UPL.txt
+
+import difflib
+import re
+import os
+
+## sort file `file_name` to file `file_name.sorted`
+def sort_file(file_name):
+ if not os.path.isfile(file_name):
+ raise RuntimeError("Missing file '{}'".format(file_name))
+
+ output_file = "{}.sorted".format(file_name)
+
+ with open(file_name) as f:
+ digits = re.compile(r'^\d+$')
+ def prepare_row(row):
+ return list(map(
+ # natural sort, transfor integers to string representation with leading zeroes
+ lambda field: (("{:0>20d}".format(int(field))) if digits.match(field) else field),
+ row.split("\t")))
+
+ rows = sorted([row.rstrip() for row in f], key=lambda row: prepare_row(row))
+
+ with open(output_file, "w") as f:
+ f.write("\n".join(rows))
+
+ return None
+
+## Compare two given files. Exit with error status if files do not match.
+def compare_files(expected_file, actual_file):
+ if not os.path.isfile(expected_file):
+ raise RuntimeError("Missing file '{}'".format(expected_file))
+ if not os.path.isfile(actual_file):
+ raise RuntimeError("Missing file '{}'".format(actual_file))
+
+ with open(expected_file) as f:
+ expected_lines = [line.rstrip() for line in f]
+
+ with open(actual_file) as f:
+ actual_lines = [line.rstrip() for line in f]
+
+ if actual_lines != expected_lines:
+ os.sys.stdout.writelines(difflib.unified_diff(open(expected_file).readlines(), open(actual_file).readlines(), fromfile=expected_file, tofile=actual_file))
+ os.sys.exit("Found output difference, expected file:'{}', actual file:'{}".format(expected_file, actual_file))
+
+ return True
+
+## Compare `file_name` with `file_name.expected`. Exit with error status if files do not match.
+def compare_file(file_name):
+ actual_file = file_name
+ expected_file = "{}.expected".format(file_name)
+
+ return compare_files(expected_file, actual_file)
+
+## Compare `file_name.sorted` with `file_name.expected.sorted`. Exit with error status if files do not match.
+def compare_sorted_file(file_name):
+ actual_file = "{}.sorted".format(file_name)
+ expected_file = "{}.expected.sorted".format(file_name)
+
+ return compare_files(expected_file, actual_file)
+
diff --git a/cmake/redirect.py b/cmake/redirect.py
new file mode 100644
index 00000000000..d1b703e61a3
--- /dev/null
+++ b/cmake/redirect.py
@@ -0,0 +1,44 @@
+# Souffle - A Datalog Compiler
+# Copyright (c) 2022 The Souffle Developers. All rights reserved
+# Licensed under the Universal Permissive License v 1.0 as shown at:
+# - https://opensource.org/licenses/UPL
+# - /licenses/SOUFFLE-UPL.txt
+
+import os
+import argparse
+import pathlib
+import subprocess
+
+parser = argparse.ArgumentParser(description="Redirect standard streams")
+parser.add_argument('--in', dest='in_file')
+parser.add_argument('--out', dest='out_file')
+parser.add_argument('--err', dest='err_file')
+parser.add_argument('command', type=lambda p: pathlib.Path(p).absolute())
+parser.add_argument('arguments', nargs=argparse.REMAINDER)
+
+args = parser.parse_args()
+
+if args.in_file:
+ stdin = open(args.in_file)
+else:
+ stdin = None
+
+if args.out_file:
+ stdout = open(args.out_file, "w")
+else:
+ stdout = None
+
+if args.err_file:
+ stderr = open(args.err_file, "w")
+else:
+ stderr = None
+
+status = subprocess.run([args.command] + args.arguments, stdin=stdin, stdout=stdout, stderr=stderr)
+
+if stdout:
+ stdout.close()
+
+if stderr:
+ stderr.close()
+
+os.sys.exit(status.returncode)
diff --git a/cmake/setup_test_dir.py b/cmake/setup_test_dir.py
new file mode 100644
index 00000000000..7a2fb1b300c
--- /dev/null
+++ b/cmake/setup_test_dir.py
@@ -0,0 +1,88 @@
+# Souffle - A Datalog Compiler
+# Copyright (c) 2022 The Souffle Developers. All rights reserved
+# Licensed under the Universal Permissive License v 1.0 as shown at:
+# - https://opensource.org/licenses/UPL
+# - /licenses/SOUFFLE-UPL.txt
+
+import glob
+import os
+import shutil
+from common import *
+
+args = os.sys.argv
+args.pop(0)
+
+if len(args) == 0:
+ raise RuntimeError("Missing INPUT_DIR")
+input_dir = args.pop(0)
+
+if len(args) == 0:
+ raise RuntimeError("Missing OUTPUT_DIR")
+output_dir = args.pop(0)
+
+if len(args) == 0:
+ raise RuntimeError("Missing TEST_NAME")
+test_name = args.pop(0)
+
+if len(args) > 0:
+ extra_data = args.pop(0)
+else:
+ extra_data = None
+
+if len(args) != 0:
+ raise RuntimeError("Unexpected argument")
+
+if os.path.exists(output_dir) and (not os.path.isdir(output_dir)):
+ raise RuntimeError("Output path exists but is not a directory")
+
+# clean output directory
+if os.path.isdir(output_dir):
+ for file in os.listdir(output_dir):
+ path = os.path.join(output_dir, file)
+ if os.path.isdir(path):
+ shutil.rmtree(path) # only remove directories
+ else:
+ os.remove(path) # only remove files
+else:
+ os.makedirs(output_dir, exist_ok=True)
+
+if extra_data == "json":
+ for file in [os.path.basename(p) for p in glob.glob(os.path.join(input_dir,"*.json"))]:
+ shutil.copyfile(
+ os.path.join(input_dir, file),
+ os.path.join(output_dir, "{}.expected".format(file)))
+elif extra_data == "python" or extra_data == "java":
+ shutil.copyfile(
+ os.path.join(input_dir, "{}-{}.out".format(test_name, extra_data)),
+ os.path.join(output_dir, "{}-{}.out.expected".format(test_name, extra_data)))
+elif extra_data == "provenance":
+ shutil.copyfile(
+ os.path.join(input_dir, "{}.in".format(test_name)),
+ os.path.join(output_dir, "{}.in".format(test_name)))
+
+shutil.copyfile(
+ os.path.join(input_dir, "{}.out".format(test_name)),
+ os.path.join(output_dir, "{}.out.expected".format(test_name)))
+
+shutil.copyfile(
+ os.path.join(input_dir, "{}.err".format(test_name)),
+ os.path.join(output_dir, "{}.err.expected".format(test_name)))
+
+csvs = [os.path.basename(p) for p in glob.glob(os.path.join(input_dir,"*.csv"))]
+
+with open(os.path.join(output_dir, "num.expected"), "w") as num_file:
+ num_file.write("{}\n".format(len(csvs)))
+
+for file in csvs:
+ shutil.copyfile(
+ os.path.join(input_dir, file),
+ os.path.join(output_dir, "{}.expected".format(file)))
+
+owd = os.getcwd()
+try:
+ os.chdir(output_dir)
+ for file in glob.glob("*.expected"):
+ sort_file(file)
+finally:
+ os.chdir(owd)
+
diff --git a/cmake/setup_test_dir.sh b/cmake/setup_test_dir.sh
deleted file mode 100755
index bf592fd8c70..00000000000
--- a/cmake/setup_test_dir.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-# Souffle - A Datalog Compiler
-# Copyright (c) 2021 The Souffle Developers. All rights reserved
-# Licensed under the Universal Permissive License v 1.0 as shown at:
-# - https://opensource.org/licenses/UPL
-# - /licenses/SOUFFLE-UPL.txt
-
-set -e
-
-INPUT_DIR="$1"
-OUTPUT_DIR="$2"
-TEST_NAME="$3"
-EXTRA_DATA="$4"
-
-mkdir -p "${OUTPUT_DIR}"
-rm -rf "${OUTPUT_DIR}"/*
-
-if [ -z ${EXTRA_DATA} ]; then
- EXTRA_DATA="nothing"
-fi
-
-if [ ${EXTRA_DATA} = "json" ]; then
- # The json tests require additional shenanigans
- sed 's/\(@<:@@:>@,@:>@\)$/\\1/' "${INPUT_DIR}/${TEST_NAME}.out" > "${OUTPUT_DIR}/${TEST_NAME}.out.expected"
-
- for file in $(cd "${INPUT_DIR}" && find . -maxdepth 1 -name "*.json"); do
- sed 's/\(@<:@@:>@,@:>@\)$/\\1/' "${INPUT_DIR}/${file}" > "${OUTPUT_DIR}/${file}.expected"
- done
-else
- cp "${INPUT_DIR}/${TEST_NAME}.out" "${OUTPUT_DIR}/${TEST_NAME}.out.expected"
-
- if [ ${EXTRA_DATA} = "python" ] || [ ${EXTRA_DATA} = "java" ]; then
- cp "${INPUT_DIR}/${TEST_NAME}-${EXTRA_DATA}.out" "${OUTPUT_DIR}/${TEST_NAME}-${EXTRA_DATA}.out.expected"
- fi
-
- if [ ${EXTRA_DATA} = "provenance" ]; then
- cp "${INPUT_DIR}/${TEST_NAME}.in" "${OUTPUT_DIR}/${TEST_NAME}.in"
- fi
-fi
-
-cp "${INPUT_DIR}/${TEST_NAME}".err "${OUTPUT_DIR}/${TEST_NAME}".err.expected
-
-for file in $(cd "${INPUT_DIR}" && find . -maxdepth 1 -name "*.csv"); do
- cp "${INPUT_DIR}/$file" "${OUTPUT_DIR}/${file}.expected"
-done
-
-find "${INPUT_DIR}" -maxdepth 1 -name "*.csv" | wc -l > "${OUTPUT_DIR}/num.expected"
-
-for file in $(cd "${OUTPUT_DIR}" && find . -maxdepth 1 -name "*.expected"); do
- sort "${OUTPUT_DIR}/$file" > "${OUTPUT_DIR}/${file}.sorted"
-done
diff --git a/sh/setup/install_ubuntu_deps.sh b/sh/setup/install_ubuntu_deps.sh
index 4bba4a6b557..68bd1a95b87 100755
--- a/sh/setup/install_ubuntu_deps.sh
+++ b/sh/setup/install_ubuntu_deps.sh
@@ -3,4 +3,4 @@
# Install Ubuntu dependencies on a Github Action VM
apt-get update -q
-apt-get install -y -q bash-completion bison build-essential clang debhelper default-jdk-headless devscripts doxygen fakeroot flex g++ gdb git graphviz libffi-dev libncurses5-dev libsqlite3-dev libtool make mcpp pkg-config python3-dev sqlite swig zlib1g-dev cmake
+apt-get install -y -q bash-completion bison build-essential clang debhelper default-jdk-headless devscripts doxygen fakeroot flex g++ gdb git graphviz libffi-dev libncurses5-dev libsqlite3-dev libtool make mcpp pkg-config python3-dev sqlite swig zlib1g-dev cmake ruby
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0fa0cc7625b..583e2988179 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,6 +4,7 @@
# - https://opensource.org/licenses/UPL
# - /licenses/SOUFFLE-UPL.txt
+
set(SOUFFLE_SOURCES
FunctorOps.cpp
Global.cpp
@@ -160,14 +161,25 @@ set(SOUFFLE_SOURCES
# Flex/Bison
# --------------------------------------------------
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/parser")
-flex_target(scanner parser/scanner.ll ${CMAKE_CURRENT_BINARY_DIR}/parser/scanner.cc)
+
+flex_target(scanner parser/scanner.ll ${CMAKE_CURRENT_BINARY_DIR}/parser/scanner.cc
+ COMPILE_FLAGS "${SCANNER_COMPILE_FLAGS} -d")
+
bison_target(parser parser/parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser/parser.cc
COMPILE_FLAGS "-Wall -Werror -Wno-error=deprecated -Wno-error=other -v -d")
add_flex_bison_dependency(scanner parser)
-# OSX compiler doesn't recognise `(void)var;` ideom
-set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser/scanner.cc PROPERTIES
+
+if (MSVC)
+ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser/scanner.cc PROPERTIES
+ COMPILE_FLAGS "/wd4005 /wd4996")
+ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser/parser.cc PROPERTIES
+ COMPILE_FLAGS "/wd4005 /wd26819")
+else ()
+ # OSX compiler doesn't recognise `(void)var;` ideom
+ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser/scanner.cc PROPERTIES
COMPILE_FLAGS "-Wno-error=unused-parameter")
+endif ()
# --------------------------------------------------
# Souffle library
@@ -190,57 +202,92 @@ target_include_directories(libsouffle
# install souffle directory
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/souffle DESTINATION include)
+add_library(compiled STATIC dummy.cpp)
+
+target_include_directories(compiled PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
+
# Set C++ standard to C++17
-target_compile_features(libsouffle
- PUBLIC cxx_std_17)
+target_compile_features(libsouffle PUBLIC cxx_std_17)
+target_compile_features(compiled PUBLIC cxx_std_17)
+
set_target_properties(libsouffle PROPERTIES CXX_EXTENSIONS OFF)
+set_target_properties(compiled PROPERTIES CXX_EXTENSIONS OFF)
+
+if (NOT MSVC)
+ target_compile_options(libsouffle PUBLIC -Wall -Wextra -Werror -fwrapv)
+else ()
+ target_compile_options(libsouffle PUBLIC /W3 /WX)
+endif ()
-target_compile_options(libsouffle
- PUBLIC "-Wall;-Wextra;-Werror;-fwrapv")
+target_compile_options(compiled PUBLIC "")
+
+if (Threads_FOUND)
+ target_link_libraries(libsouffle PUBLIC Threads::Threads)
+ target_link_libraries(compiled PUBLIC Threads::Threads)
+endif ()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
+ target_link_libraries(libsouffle PUBLIC stdc++fs)
+ target_link_libraries(compiled PUBLIC stdc++fs)
+ endif ()
+endif ()
-target_link_libraries(libsouffle PRIVATE Threads::Threads)
if(SOUFFLE_CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_link_libraries(libsouffle PUBLIC coverage_config)
-endif(SOUFFLE_CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+endif ()
-# FIXME: Better to have a library list
-if (OPENMP_FOUND)
- target_link_libraries(libsouffle
- PUBLIC OpenMP::OpenMP_CXX
- $<$:ZLIB::ZLIB>
- $<$:SQLite::SQLite3>
- $<$:Curses::NCurses>
- $<$:LibFFI::LibFFI>
- "${CMAKE_DL_LIBS}")
-else()
- target_link_libraries(libsouffle
- PUBLIC $<$:ZLIB::ZLIB>
- $<$:SQLite::SQLite3>
- $<$:Curses::NCurses>
- $<$:LibFFI::LibFFI>
- "${CMAKE_DL_LIBS}")
-endif()
+
+target_link_libraries(libsouffle PUBLIC "${CMAKE_DL_LIBS}")
+target_link_libraries(compiled PUBLIC "${CMAKE_DL_LIBS}")
if (SOUFFLE_DOMAIN_64BIT)
+ target_compile_definitions(libsouffle PUBLIC RAM_DOMAIN_SIZE=64)
+ target_compile_definitions(compiled PUBLIC RAM_DOMAIN_SIZE=64)
+endif()
+
+if (SOUFFLE_USE_LIBFFI)
+if (libffi_FOUND)
+ target_link_libraries(libsouffle PUBLIC libffi)
+else ()
+ target_link_libraries(libsouffle PUBLIC LibFFI::LibFFI)
+endif ()
+endif ()
+
+if (OPENMP_FOUND)
+ target_link_libraries(libsouffle PUBLIC OpenMP::OpenMP_CXX)
+ target_link_libraries(compiled PUBLIC OpenMP::OpenMP_CXX)
+endif()
+
+if (SOUFFLE_CUSTOM_GETOPTLONG)
target_compile_definitions(libsouffle
- PUBLIC RAM_DOMAIN_SIZE=64)
+ PUBLIC USE_CUSTOM_GETOPTLONG)
+ target_compile_definitions(compiled
+ PUBLIC USE_CUSTOM_GETOPTLONG)
endif()
if (SOUFFLE_USE_CURSES)
- target_compile_definitions(libsouffle
- PUBLIC USE_NCURSES)
+ target_compile_definitions(libsouffle PUBLIC USE_NCURSES)
+ target_compile_definitions(compiled PUBLIC USE_NCURSES)
+ target_link_libraries(libsouffle PUBLIC Curses::NCurses)
+ target_link_libraries(compiled PUBLIC Curses::NCurses)
endif()
if (SOUFFLE_USE_ZLIB)
- target_compile_definitions(libsouffle
- PUBLIC USE_LIBZ)
+ target_compile_definitions(libsouffle PUBLIC USE_LIBZ)
+ target_compile_definitions(compiled PUBLIC USE_LIBZ)
+ target_link_libraries(libsouffle PUBLIC ZLIB::ZLIB)
+ target_link_libraries(compiled PUBLIC ZLIB::ZLIB)
endif()
if (SOUFFLE_USE_SQLITE)
- target_compile_definitions(libsouffle
- PUBLIC USE_SQLITE)
+ target_compile_definitions(libsouffle PUBLIC USE_SQLITE)
+ target_compile_definitions(compiled PUBLIC USE_SQLITE)
+ target_link_libraries(libsouffle PUBLIC SQLite::SQLite3)
+ target_link_libraries(compiled PUBLIC SQLite::SQLite3)
+ target_include_directories(compiled PUBLIC ${SQLite3_INCLUDE_DIRS})
endif()
if (SOUFFLE_USE_LIBFFI)
@@ -263,84 +310,231 @@ add_executable(souffle
target_link_libraries(souffle libsouffle)
install(TARGETS souffle DESTINATION bin)
+# Copy the dlls in the same directory as Souffle so that they will
+# be immediately found by the operating system.
+
+if (SOUFFLE_USE_SQLITE)
+add_custom_command(TARGET souffle POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${SQLite3_LIBRARY} ${ZLIB_LIBRARY_RELEASE}
+ $)
+endif ()
+
+if (SOUFFLE_USE_ZLIB)
+add_custom_command(TARGET souffle POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${SQLite3_LIBRARY} ${ZLIB_LIBRARY_RELEASE}
+ $)
+endif ()
+
+if (SOUFFLE_USE_CURSES)
+add_custom_command(TARGET souffle POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ ${CURSES_NCURSES_LIBRARY}
+ $)
+endif ()
+
# --------------------------------------------------
# Souffle's profiler binary
# --------------------------------------------------
+if (NOT WIN32)
+ add_executable(souffleprof
+ souffle_prof.cpp)
+ target_include_directories(souffleprof PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
+ install(TARGETS souffleprof DESTINATION bin)
+
+ # Set C++ standard to C++17
+ target_compile_features(souffleprof
+ PUBLIC cxx_std_17)
+endif()
+
+if (MSVC)
+ target_compile_options(libsouffle PUBLIC /bigobj)
+ target_compile_options(compiled PUBLIC /bigobj)
+
+ target_compile_options(libsouffle PUBLIC /wd5105)
+ target_compile_options(compiled PUBLIC /wd5105)
+
+ target_compile_options(libsouffle PUBLIC /wd6326)
+ target_compile_options(compiled PUBLIC /wd6326)
+
+ target_compile_options(libsouffle PUBLIC /wd26110)
+ target_compile_options(libsouffle PUBLIC /wd4065 /wd4200)
+
+ # to prevent old versions of Flex from redeclaring int types
+ target_compile_definitions(libsouffle PRIVATE __STDC_LIMIT_MACROS)
+
+ target_compile_definitions(libsouffle PUBLIC _CRT_SECURE_NO_WARNINGS)
+
+ if (NOT (MSVC_VERSION LESS 1910))
+ target_compile_options(libsouffle PUBLIC /permissive-)
+ target_compile_options(compiled PUBLIC /permissive-)
+ endif()
+
+ target_compile_options(libsouffle PUBLIC /Zc:preprocessor)
+ target_compile_options(compiled PUBLIC /Zc:preprocessor)
+
+ target_compile_options(libsouffle PUBLIC /EHsc)
+ target_compile_options(compiled PUBLIC /EHsc)
+
+ target_compile_definitions(libsouffle PUBLIC USE_CUSTOM_GETOPTLONG)
+ target_compile_definitions(compiled PUBLIC USE_CUSTOM_GETOPTLONG)
+endif (MSVC)
-add_executable(souffleprof
- souffle_prof.cpp)
-target_include_directories(souffleprof PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
-install(TARGETS souffleprof DESTINATION bin)
-# Set C++ standard to C++17
-target_compile_features(souffleprof
- PUBLIC cxx_std_17)
# --------------------------------------------------
-# Substitutions for souffle-compile
+# Substitutions for souffle-compile.py
# --------------------------------------------------
-# FIXME: This is a bit fragile but there is actually no better way
-# to do this, AFAIK
-# Maybe we could make a cmake script instead of using shell?
-function(AUTOMAKE_COMPATIBLE_SUBST F_IN F_OUT)
- # enclose in scope so we can create the
- # values to substitute
-
- set(CXX ${CMAKE_CXX_COMPILER})
-
- set(CMAKE_HEADER_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include")
-
- set(CPPFLAGS "")
-
- # Compile definitions
- get_target_property(COMP_DEFS libsouffle COMPILE_DEFINITIONS)
- set(SUBST_DEFS "")
- foreach(DEF ${COMP_DEFS})
- string(APPEND SUBST_DEFS "-D${DEF} ")
- endforeach()
-
- # Compile flags
- string(TOUPPER ${CMAKE_BUILD_TYPE} BT_UPPER)
- # Remove -Werror from the default flag set for compilation using `souffle-compile`.
- # *) `-d` option in `souffle-compile` adds this flag back
- # *) The compiler used by `souffle-compile` isn't neccesarily the same as the one used by `cmake`.
- # Code that's free of warnings w/ the cmake compiler might not be w/ `souffle-compile`'s compiler.
- # e.g. we might use clang-10, user might use gcc or some newer version of clang.
- # *) Synth'd code isn't warning free for now anyways.
- # TODO: Require/verify that test case synthesised code is warning free as part of test suite.
- string(REGEX REPLACE "-Werror" "" SOUFFLE_CXXFLAGS "${CMAKE_CXX_FLAGS}")
- set(SOUFFLE_CXXFLAGS "${SOUFFLE_CXXFLAGS} ${CMAKE_CXX_FLAGS_${BT_UPPER}} ${SUBST_DEFS}")
- if (OPENMP_FOUND)
- set(SOUFFLE_CXXFLAGS "${SOUFFLE_CXXFLAGS} -fopenmp")
- endif()
-
- # Libraries
- set(LIBS "-lpthread")
-
- if (CMAKE_DL_LIBS)
- string(APPEND LIBS " -l${CMAKE_DL_LIBS}")
- endif()
-
- if (SOUFFLE_USE_SQLITE)
- string(APPEND LIBS " ${SQLite3_LIBRARY}")
- endif()
-
- if (SOUFFLE_USE_ZLIB)
- string(APPEND LIBS " ${ZLIB_LIBRARY_RELEASE}")
- endif()
-
- if (SOUFFLE_USE_CURSES)
- string(APPEND LIBS " ${CURSES_NCURSES_LIBRARY}")
- endif()
-
- configure_file("${F_IN}" "${F_OUT}" @ONLY)
-endfunction()
-
-automake_compatible_subst("${CMAKE_CURRENT_SOURCE_DIR}/souffle-compile.in"
- "${CMAKE_CURRENT_BINARY_DIR}/souffle-compile")
-
-install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/souffle-compile DESTINATION bin)
+set(SOUFFLE_COMPILED_CXX_COMPILER ${CMAKE_CXX_COMPILER})
+set(SOUFFLE_COMPILED_CXX_COMPILER_ID ${CMAKE_CXX_COMPILER_ID})
+set(SOUFFLE_COMPILED_CXX_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION})
+set(SOUFFLE_COMPILED_CXX_STANDARD ${CMAKE_CXX17_STANDARD_COMPILE_OPTION})
+set(SOUFFLE_COMPILED_CXX_FLAGS ${CMAKE_CXX_FLAGS})
+set(SOUFFLE_COMPILED_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS})
+set(SOUFFLE_COMPILED_RELEASE_CXX_FLAGS ${CMAKE_CXX_FLAGS_RELEASE})
+set(SOUFFLE_COMPILED_DEBUG_CXX_FLAGS ${CMAKE_CXX_FLAGS_DEBUG})
+get_target_property(SOUFFLE_COMPILED_DEFS compiled COMPILE_DEFINITIONS)
+get_target_property(SOUFFLE_COMPILED_OPTS compiled COMPILE_OPTIONS)
+get_target_property(SOUFFLE_COMPILED_INCS compiled INCLUDE_DIRECTORIES)
+
+set(SOUFFLE_COMPILED_LIBS "")
+set(SOUFFLE_COMPILED_RPATHS "")
+
+if (THREADS_FOUND)
+ list(APPEND SOUFFLE_COMPILED_LIBS ${CMAKE_THREAD_LIBS_INIT})
+endif()
+
+if (OPENMP_FOUND)
+ string(APPEND SOUFFLE_COMPILED_CXX_FLAGS " ${OpenMP_CXX_FLAGS}")
+ list(APPEND SOUFFLE_COMPILED_INCS ${OpenMP_CXX_INCLUDE_DIRS})
+endif()
+
+if (CMAKE_DL_LIBS)
+ list(APPEND SOUFFLE_COMPILED_LIBS -l${CMAKE_DL_LIBS})
+endif()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
+ list(APPEND SOUFFLE_COMPILED_LIBS -lstdc++fs)
+ endif ()
+endif()
+
+if (SOUFFLE_USE_SQLITE)
+ list(APPEND SOUFFLE_COMPILED_LIBS ${SQLite3_LIBRARY})
+ if (COMMAND cmake_path)
+ cmake_path(GET SQLite3_LIBRARY PARENT_PATH SQLite3_RPATH)
+ else ()
+ get_filename_component(SQLite3_RPATH ${SQLite3_LIBRARY} DIRECTORY)
+ endif ()
+ list(APPEND SOUFFLE_COMPILED_RPATHS ${SQLite3_RPATH})
+endif()
+
+if (SOUFFLE_USE_ZLIB)
+ list(APPEND SOUFFLE_COMPILED_LIBS ${ZLIB_LIBRARY_RELEASE})
+ if (COMMAND cmake_path)
+ cmake_path(GET ZLIB_LIBRARY_RELEASE PARENT_PATH ZLIB_RPATH)
+ else ()
+ get_filename_component(ZLIB_RPATH ${ZLIB_LIBRARY_RELEASE} DIRECTORY)
+ endif ()
+ list(APPEND SOUFFLE_COMPILED_RPATHS ${ZLIB_RPATH})
+endif()
+
+if (SOUFFLE_USE_CURSES)
+ list(APPEND SOUFFLE_COMPILED_LIBS ${CURSES_NCURSES_LIBRARY})
+ if (COMMAND cmake_path)
+ cmake_path(GET CURSES_NCURSES_LIBRARY PARENT_PATH NCURSES_RPATH)
+ else ()
+ get_filename_component(NCURSES_RPATH ${CURSES_NCURSES_LIBRARY} DIRECTORY)
+ endif ()
+ list(APPEND SOUFFLE_COMPILED_RPATHS ${NCURSES_RPATH})
+endif()
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+ # using Python3 PEP 3101 Format String:
+ set(OUTNAME_FMT "-o {}")
+ set(LIBDIR_FMT "-L{}")
+ set(LIBNAME_FMT "-l{}")
+ set(RPATH_FMT "-Wl,-rpath,{}")
+ set(EXE_EXTENSION "")
+ set(OS_PATH_DELIMITER ":")
+elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ # using Python3 PEP 3101 Format String:
+ set(OUTNAME_FMT "/Fe:{}")
+ set(LIBDIR_FMT "/libpath:{}")
+ set(LIBNAME_FMT "{}.lib")
+ set(RPATH_FMT "")
+ set(EXE_EXTENSION ".exe")
+ set(OS_PATH_DELIMITER ";")
+endif ()
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ ## Is is very important that the Runtime Library match between
+ ## the Souffle compiled program and any dynamically loaded functor library.
+ if (CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "^MultiThreaded(Debug)?$")
+ # static multi-threaded library
+ string(APPEND SOUFFLE_COMPILED_DEBUG_CXX_FLAGS " /MTd")
+ string(APPEND SOUFFLE_COMPILED_RELEASE_CXX_FLAGS " /MT")
+ else ()
+ # dynamic multi-threaded library
+ string(APPEND SOUFFLE_COMPILED_DEBUG_CXX_FLAGS " /MDd")
+ string(APPEND SOUFFLE_COMPILED_RELEASE_CXX_FLAGS " /MD")
+ endif ()
+endif ()
+
+list(JOIN SOUFFLE_COMPILED_OPTS " " SOUFFLE_COMPILED_CXX_OPTIONS)
+
+list(JOIN SOUFFLE_COMPILED_LIBS " " SOUFFLE_COMPILED_LINK_OPTIONS)
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ set(SOUFFLE_COMPILED_LINK_OPTIONS "/link ${SOUFFLE_COMPILED_LINK_OPTIONS}")
+endif ()
+
+list(JOIN SOUFFLE_COMPILED_RPATHS "${OS_PATH_DELIMITER}" SOUFFLE_COMPILED_RPATH_LIST)
+
+list(TRANSFORM SOUFFLE_COMPILED_INCS PREPEND "-I")
+list(JOIN SOUFFLE_COMPILED_INCS " " SOUFFLE_COMPILED_INCLUDES)
+
+list(TRANSFORM SOUFFLE_COMPILED_DEFS PREPEND "-D")
+list(JOIN SOUFFLE_COMPILED_DEFS " " SOUFFLE_COMPILED_DEFINITIONS)
+
+file(READ ${CMAKE_CURRENT_SOURCE_DIR}/souffle-compile.template.py TEMPLATE)
+
+# json parameters injected at the begining of souffle-compile.py
+set(SOUFFLE_COMPILE_PY
+"#!/usr/bin/env python3
+JSON_DATA_TEXT = \"\"\"{
+ \"compiler\": \"${SOUFFLE_COMPILED_CXX_COMPILER}\",
+ \"compiler_id\": \"${SOUFFLE_COMPILED_CXX_COMPILER_ID}\",
+ \"compiler_version\": \"${SOUFFLE_COMPILED_CXX_COMPILER_VERSION}\",
+ \"msvc_version\": \"${MSVC_VERSION}\",
+ \"includes\": \"${SOUFFLE_COMPILED_INCLUDES}\",
+ \"std_flag\": \"${SOUFFLE_COMPILED_CXX_STANDARD}\",
+ \"cxx_flags\": \"${SOUFFLE_COMPILED_CXX_FLAGS}\",
+ \"cxx_link_flags\": \"${SOUFFLE_COMPILED_CXX_LINK_FLAGS}\",
+ \"release_cxx_flags\": \"${SOUFFLE_COMPILED_RELEASE_CXX_FLAGS}\",
+ \"debug_cxx_flags\": \"${SOUFFLE_COMPILED_DEBUG_CXX_FLAGS}\",
+ \"definitions\": \"${SOUFFLE_COMPILED_DEFINITIONS}\",
+ \"compile_options\": \"${SOUFFLE_COMPILED_CXX_OPTIONS}\",
+ \"link_options\": \"${SOUFFLE_COMPILED_LINK_OPTIONS}\",
+ \"rpaths\": \"${SOUFFLE_COMPILED_RPATH_LIST}\",
+ \"outname_fmt\": \"${OUTNAME_FMT}\",
+ \"libdir_fmt\": \"${LIBDIR_FMT}\",
+ \"libname_fmt\": \"${LIBNAME_FMT}\",
+ \"rpath_fmt\": \"${RPATH_FMT}\",
+ \"path_delimiter\": \"${OS_PATH_DELIMITER}\",
+ \"exe_extension\": \"${EXE_EXTENSION}\",
+ \"source_include_dir\": \"${CMAKE_CURRENT_SOURCE_DIR}/include\",
+ \"jni_includes\": \"${JAVA_INCLUDE_PATH}${OS_PATH_DELIMITER}${JAVA_INCLUDE_PATH2}\"
+}\"\"\"
+${TEMPLATE}
+")
+
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/souffle-compile.py" CONTENT "${SOUFFLE_COMPILE_PY}")
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/souffle-compile.py DESTINATION bin)
+
+# ---------------------------------------
# FIXME: Ideally, eventually we will move these out to the "tests" subdirectory
# now that we have a sane(er?) build system
diff --git a/src/Global.cpp b/src/Global.cpp
index 95bb1170306..f8436900dd8 100644
--- a/src/Global.cpp
+++ b/src/Global.cpp
@@ -15,6 +15,7 @@
***********************************************************************/
#include "Global.h"
+#include "souffle/utility/FileUtil.h"
#include "souffle/utility/StreamUtil.h"
#include "souffle/utility/StringUtil.h"
#include
@@ -25,8 +26,14 @@
#include
#include
#include
+#include
#include
+
+#ifdef USE_CUSTOM_GETOPTLONG
+#include "souffle/utility/GetOptLongImpl.h"
+#else
#include
+#endif
namespace souffle {
@@ -129,7 +136,7 @@ void MainConfig::processArgs(int argc, char** argv, const std::string& header, c
// use the main options to define the global configuration
{
// array of long names for classic getopt processing
- option longNames[mainOptions.size()];
+ std::unique_ptr