Skip to content

Commit 21eff1c

Browse files
committed
Build R-Interface with Rtools static toolchain
1 parent b1028c2 commit 21eff1c

7 files changed

Lines changed: 156 additions & 28 deletions

File tree

.github/workflows/windows.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,38 @@ jobs:
8989
env:
9090
VCINSTALLDIR: "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/"
9191

92+
- name: Check R-Interface DLL dependencies
93+
shell: pwsh
94+
run: |
95+
$objdump = "C:\rtools45\x86_64-w64-mingw32.static.posix\bin\objdump.exe"
96+
$dlls = @(
97+
"jasp-build\R-Interface\libR-Interface.dll",
98+
"jasp-build\R-Interface\libR-InterfaceNoRInside.dll"
99+
)
100+
101+
foreach ($dll in $dlls) {
102+
Write-Host "Imports for $dll"
103+
if (-not (Test-Path $dll)) {
104+
Write-Error "Missing DLL: $dll"
105+
exit 1
106+
}
107+
108+
$objdumpOutput = & $objdump -p $dll
109+
if ($LASTEXITCODE -ne 0) {
110+
Write-Error "objdump failed for $dll"
111+
exit $LASTEXITCODE
112+
}
113+
114+
$imports = $objdumpOutput | Select-String -Pattern "DLL Name"
115+
$imports
116+
117+
$forbidden = $imports | Select-String -Pattern "libgcc|libstdc\+\+|libwinpthread"
118+
if ($forbidden) {
119+
Write-Error "Unexpected MinGW runtime dependency in $dll"
120+
exit 1
121+
}
122+
}
123+
92124
- name: Run Tests
93125
shell: pwsh
94126
run: |

CMakeLists.txt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,16 +206,21 @@ else()
206206
${CMAKE_BINARY_DIR}/R-Interface/libR-InterfaceNoRInside.dll
207207
${CMAKE_BINARY_DIR}/R-Interface/libR-InterfaceNoRInside.dll.a
208208
COMMAND
209-
${CMAKE_COMMAND} -G "MinGW Makefiles" -S . -B
210-
${CMAKE_BINARY_DIR}/R-Interface "-DRTOOLS_PATH:PATH=${RTOOLS_PATH}"
209+
${CMAKE_COMMAND} -E env
210+
"PATH=${RTOOLS_STATIC_TOOLCHAIN_BIN};${RTOOLS_BUILD_TOOLS_BIN};$ENV{PATH}"
211+
${CMAKE_COMMAND} -G "${RTOOLS_R_INTERFACE_GENERATOR}" -S . -B
212+
${CMAKE_BINARY_DIR}/R-Interface
211213
"-DCMAKE_C_COMPILER:PATH=${RTOOLS_C_COMPILER}"
212214
"-DCMAKE_CXX_COMPILER:PATH=${RTOOLS_CXX_COMPILER}"
213215
"-DCMAKE_MAKE_PROGRAM:PATH=${RTOOLS_MAKE_PROGRAM}"
214216
"-DJASP_BINARY_DIR:PATH=${CMAKE_BINARY_DIR}"
215217
"-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
216218
"-DR_VERSION:STRING=${R_VERSION}"
217-
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/R-Interface
218-
USES_TERMINAL
219+
COMMAND
220+
${CMAKE_COMMAND} -E env
221+
"PATH=${RTOOLS_STATIC_TOOLCHAIN_BIN};${RTOOLS_BUILD_TOOLS_BIN};$ENV{PATH}"
222+
${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/R-Interface
223+
VERBATIM
219224
COMMENT "------ Configuring and Building the libR-Interface")
220225

221226
add_dependencies(SyntaxInterface R-Interface)

Desktop/gui/jaspConfiguration/jaspconfigurationtomlparser.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,18 @@ bool JASPConfigurationTOMLParser::parse(JASPConfiguration *target, const QString
1414

1515
try
1616
{
17-
tbl = toml::parse(input.toStdString());
17+
auto result = toml::parse(input.toStdString());
18+
if(!result)
19+
{
20+
Log::log() << "Parsing failed: " << result.error() << std::endl;
21+
return false;
22+
}
23+
tbl = std::move(result).table();
1824
}
1925
catch (const toml::parse_error& err)
2026
{
2127
Log::log() << "Parsing failed: " << err << std::endl;
28+
return false;
2229
}
2330

2431
//jasp version

Desktop/mainwindow.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <QMenuBar>
3131
#include <exception>
3232
#include <iostream>
33+
#include <streambuf>
3334

3435
#include "log.h"
3536
#include "timers.h"
@@ -65,14 +66,28 @@
6566
#include "rsyntax/formulabase.h"
6667
#include "utilities/desktopcommunicator.h"
6768

68-
#include "boost/iostreams/stream.hpp"
69-
#include <boost/iostreams/device/null.hpp>
70-
7169
#include "communitydefs.h"
7270

7371
using namespace std;
7472
using namespace Modules;
7573

74+
namespace
75+
{
76+
class NullBuffer : public std::streambuf
77+
{
78+
protected:
79+
int_type overflow(int_type ch) override { return traits_type::not_eof(ch); }
80+
std::streamsize xsputn(const char *, std::streamsize count) override { return count; }
81+
};
82+
83+
std::ostream & nullOutputStream()
84+
{
85+
static NullBuffer buffer;
86+
static std::ostream stream(&buffer);
87+
return stream;
88+
}
89+
}
90+
7691
MainWindow * MainWindow::_singleton = nullptr;
7792

7893
MainWindow::MainWindow(Application * application) : QObject(application), _application(application)
@@ -894,7 +909,7 @@ void MainWindow::initLog()
894909
{
895910
assert(_engineSync != nullptr && _preferences != nullptr);
896911

897-
static boost::iostreams::stream<boost::iostreams::null_sink> nullstream((boost::iostreams::null_sink())); //https://stackoverflow.com/questions/8243743/is-there-a-null-stdostream-implementation-in-c-or-libraries
912+
std::ostream & nullstream = nullOutputStream();
898913

899914
Log::logFileNameBase = (AppDirs::logDir() + "JASP " + getSortableTimestamp()).toStdString();
900915
Log::init(&nullstream);

Engine/main.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,28 @@
2121
#include <iostream>
2222
#include <fstream>
2323
#include <codecvt>
24+
#include <streambuf>
2425
#include "otoolstuff.h"
2526
#include "dirs.h"
26-
#include "boost/iostreams/stream.hpp"
27-
#include <boost/iostreams/device/null.hpp>
2827
#include "rbridge.h"
2928

29+
namespace
30+
{
31+
class NullBuffer : public std::streambuf
32+
{
33+
protected:
34+
int_type overflow(int_type ch) override { return traits_type::not_eof(ch); }
35+
std::streamsize xsputn(const char *, std::streamsize count) override { return count; }
36+
};
37+
38+
std::ostream & nullOutputStream()
39+
{
40+
static NullBuffer buffer;
41+
static std::ostream stream(&buffer);
42+
return stream;
43+
}
44+
}
45+
3046
#ifdef _WIN32
3147
void openConsoleOutput(unsigned long slaveNo, unsigned parentPID)
3248
{
@@ -78,7 +94,7 @@ int main(int argc, char *argv[])
7894
Dirs::setReportingDir(argv[5]);
7995

8096
#endif
81-
static boost::iostreams::stream<boost::iostreams::null_sink> nullstream((boost::iostreams::null_sink())); //https://stackoverflow.com/questions/8243743/is-there-a-null-stdostream-implementation-in-c-or-libraries
97+
std::ostream & nullstream = nullOutputStream();
8298
Log::logFileNameBase = logFileBase;
8399
Log::init(&nullstream);
84100
Log::setLogFileName(logFileBase + " Engine " + std::to_string(slaveNo) + ".log");

Tools/CMake/Deploy.win.cmake.in

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
# This file is generated from `Deploy.win.cmake.in`.
22
#
3-
# It is being used to run the `macdeployqt` on the `JASP.app` binary, as well
4-
# as the JASPEngine
3+
# It is being used to run `windeployqt` on the installed JASP binaries.
4+
5+
set(_JASP_INSTALL_BINDIR "${CMAKE_INSTALL_PREFIX}")
56

67
execute_process(
78
COMMAND_ECHO STDOUT
8-
WORKING_DIRECTORY "@CMAKE_INSTALL_PREFIX@"
9+
WORKING_DIRECTORY "${_JASP_INSTALL_BINDIR}"
910
COMMAND
10-
@CMAKE_BINARY_DIR@/deploy.cmd
11+
"@DEPLOYQT_EXECUTABLE@"
12+
@WINDEPLOY_QT_BUILD_TYPE@
13+
"--qmldir=@JASP_QML_FILES@"
14+
"${_JASP_INSTALL_BINDIR}/JASPDesktop.exe"
15+
"${_JASP_INSTALL_BINDIR}/JASPEngine.exe"
1116
RESULT_VARIABLE result)
1217

1318
if(result)

Tools/CMake/Programs.cmake

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -130,23 +130,55 @@ endif()
130130

131131
if(WIN32)
132132

133+
set(_QT_DEPLOY_BIN_HINTS)
134+
foreach(_QT_PREFIX IN LISTS CMAKE_PREFIX_PATH)
135+
if(EXISTS "${_QT_PREFIX}/bin")
136+
list(APPEND _QT_DEPLOY_BIN_HINTS "${_QT_PREFIX}/bin")
137+
endif()
138+
endforeach()
139+
133140
find_program(
134-
DEPLOYQT_EXECUTABLE
135-
NAMES windeployqt
136-
PATHS ${Qt6_DIR}/bin)
141+
_DEPLOYQT_EXECUTABLE_FROM_PREFIX
142+
NAMES windeployqt windeployqt.exe
143+
PATHS ${_QT_DEPLOY_BIN_HINTS}
144+
NO_DEFAULT_PATH)
145+
146+
if(_DEPLOYQT_EXECUTABLE_FROM_PREFIX)
147+
set(DEPLOYQT_EXECUTABLE
148+
"${_DEPLOYQT_EXECUTABLE_FROM_PREFIX}"
149+
CACHE FILEPATH "Path to the windeployqt executable matching the configured Qt prefix"
150+
FORCE)
151+
else()
152+
find_program(DEPLOYQT_EXECUTABLE NAMES windeployqt windeployqt.exe)
153+
endif()
137154

138-
# look for Rtools from most newest to oldest
139-
message(CHECK_START "Looking for Rtools $ENV{RTOOLS45_HOME}")
155+
message(STATUS " ${DEPLOYQT_EXECUTABLE}")
156+
157+
message(CHECK_START "Looking for Rtools $ENV{RTOOLS45_HOME}")
140158
if(DEFINED ENV{RTOOLS45_HOME})
141-
set(RTOOLS_PATH "$ENV{RTOOLS45_HOME}/ucrt64" CACHE PATH "Path to Rtools45 x64 folder, e.g., C:/rtools45/ucrt64")
159+
file(TO_CMAKE_PATH "$ENV{RTOOLS45_HOME}" _RTOOLS45_HOME)
160+
set(RTOOLS_ROOT "${_RTOOLS45_HOME}" CACHE PATH "Path to Rtools45 installation root, e.g., C:/rtools45")
142161
else()
143-
set(RTOOLS_PATH "C:/rtools45/ucrt64" CACHE PATH "Path to Rtools45 x64 folder, e.g., C:/rtools45/ucrt64")
162+
set(RTOOLS_ROOT "C:/rtools45" CACHE PATH "Path to Rtools45 installation root, e.g., C:/rtools45")
144163
endif()
164+
set(RTOOLS_PATH "${RTOOLS_ROOT}/ucrt64" CACHE PATH "Path to Rtools45 UCRT64 package folder, e.g., C:/rtools45/ucrt64")
165+
166+
get_filename_component(_RTOOLS_ROOT_FROM_UCRT "${RTOOLS_PATH}" DIRECTORY)
167+
set(RTOOLS_STATIC_TOOLCHAIN_PATH
168+
"${_RTOOLS_ROOT_FROM_UCRT}/x86_64-w64-mingw32.static.posix"
169+
CACHE PATH
170+
"Path to Rtools45 static.posix compiler toolchain, e.g., C:/rtools45/x86_64-w64-mingw32.static.posix")
171+
set(RTOOLS_BUILD_TOOLS_PATH
172+
"${_RTOOLS_ROOT_FROM_UCRT}/usr"
173+
CACHE PATH
174+
"Path to Rtools45 MSYS build tools, e.g., C:/rtools45/usr")
145175

146176
if(EXISTS ${RTOOLS_PATH})
147177

148178
message(CHECK_PASS "found")
149-
message(STATUS " ${RTOOLS_PATH}")
179+
message(STATUS " UCRT package path: ${RTOOLS_PATH}")
180+
message(STATUS " static toolchain: ${RTOOLS_STATIC_TOOLCHAIN_PATH}")
181+
message(STATUS " build tools: ${RTOOLS_BUILD_TOOLS_PATH}")
150182

151183
message(CHECK_START
152184
"Looking for Rtools legacy and auto remove it, if not work please remove such `RTOOLS44_HOME` manually from Windows environment settings."
@@ -164,10 +196,23 @@ if(WIN32)
164196
else()
165197
message(
166198
FATAL_ERROR
167-
"Rtools not found. Rtools is required for building on Windows, please follow the build instruction before you continue. If you have installed the MINGW in a custom location, you can set the RTOOLS_PATH to your MinGW x64 path, e.g., C:/rtools45/ucrt64"
199+
"Rtools not found. Rtools is required for building on Windows, please follow the build instruction before you continue. If you have installed the MINGW in a custom location, you can set the RTOOLS_PATH to your UCRT64 package path, e.g., C:/rtools45/ucrt64"
168200
)
169201
endif()
170202

203+
if(NOT EXISTS "${RTOOLS_STATIC_TOOLCHAIN_PATH}/bin/gcc.exe"
204+
OR NOT EXISTS "${RTOOLS_STATIC_TOOLCHAIN_PATH}/bin/g++.exe")
205+
message(
206+
FATAL_ERROR
207+
"Rtools static.posix compiler toolchain not found. Set RTOOLS_STATIC_TOOLCHAIN_PATH to the Rtools static toolchain path, e.g., C:/rtools45/x86_64-w64-mingw32.static.posix")
208+
endif()
209+
210+
if(NOT EXISTS "${RTOOLS_BUILD_TOOLS_PATH}/bin/make.exe")
211+
message(
212+
FATAL_ERROR
213+
"Rtools MSYS make not found. Set RTOOLS_BUILD_TOOLS_PATH to the Rtools build tools path, e.g., C:/rtools45/usr")
214+
endif()
215+
171216
if(DEFINED ENV{WIX})
172217
set(WIX_PATH "$ENV{WIX}/bin" CACHE PATH "Path to your WIX installation, e.g., C:\\Program Files (x86)\\WiX Toolset v3.11\\bin")
173218
else()
@@ -207,9 +252,12 @@ if(WIN32)
207252
LIGHT_EXECUTABLE_NATIVE)
208253
message(STATUS " ${LIGHT_EXECUTABLE_NATIVE}")
209254

210-
set(RTOOLS_C_COMPILER "${RTOOLS_PATH}/bin/gcc.exe")
211-
set(RTOOLS_CXX_COMPILER "${RTOOLS_PATH}/bin/g++.exe")
212-
set(RTOOLS_MAKE_PROGRAM "${RTOOLS_PATH}/bin/mingw32-make.exe")
255+
set(RTOOLS_STATIC_TOOLCHAIN_BIN "${RTOOLS_STATIC_TOOLCHAIN_PATH}/bin")
256+
set(RTOOLS_BUILD_TOOLS_BIN "${RTOOLS_BUILD_TOOLS_PATH}/bin")
257+
set(RTOOLS_C_COMPILER "${RTOOLS_STATIC_TOOLCHAIN_BIN}/gcc.exe")
258+
set(RTOOLS_CXX_COMPILER "${RTOOLS_STATIC_TOOLCHAIN_BIN}/g++.exe")
259+
set(RTOOLS_MAKE_PROGRAM "${RTOOLS_BUILD_TOOLS_BIN}/make.exe")
260+
set(RTOOLS_R_INTERFACE_GENERATOR "Unix Makefiles")
213261

214262
endif()
215263

0 commit comments

Comments
 (0)