Skip to content

Commit

Permalink
Support emscripten build with PBRST support, also via cmake
Browse files Browse the repository at this point in the history
  • Loading branch information
kovzol committed Feb 10, 2025
1 parent d5626e5 commit eac4c92
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 76 deletions.
39 changes: 28 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
# This cmake configuration file has been successfully tested on the following platforms:
# Linux, macOS, MSYS2/MINGW64, emscripten.

# When building for emscripten, build a native Linux version first, create the addbooks cache,
# and just then start the build for emscripten, providing the bibref-addbooks-cache folder name
# as an option when starting cmake. See the variable BIBREF_ADDBOOKS_CACHE_FOLDER below.

cmake_minimum_required(VERSION 3.16)
project(bibref)

option(PBRST "Include the brst parser" OFF)
set(BIBREF_ADDBOOKS_CACHE_FOLDER ../bibref-addbooks-cache CACHE STRING
"Set the previously created bibref-addbooks-cache folder for the Emscripten build")

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "-pedantic-errors")

find_package(PkgConfig REQUIRED)
pkg_check_modules(sword REQUIRED sword)

if(EMSCRIPTEN)
find_library(SWORD_LIB NAMES libsword.a)
endif(EMSCRIPTEN)

set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost CONFIG COMPONENTS system filesystem)

if(APPLE) # readline seems to have trouble on MacOS
if(APPLE OR EMSCRIPTEN) # readline seems to have trouble on macOS, unsupported on emscripten
else()
# One needs readline >= 8.0 to make this work:
pkg_check_modules (readline REQUIRED readline)
endif()

include_directories(${sword_INCLUDE_DIRS})

if(PBRST)
add_compile_definitions(WITH_PBRST)

set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}")
find_package(FLEX 2.6 REQUIRED)
find_package(BISON 3.0 REQUIRED)
Expand All @@ -38,7 +47,7 @@ bison_target(PARSER "${CMAKE_CURRENT_SOURCE_DIR}/statements/pbrst.y" "${PARSER_O
add_flex_bison_dependency(LEXER PARSER)

include_directories(${PARSER_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DYYDEBUG=1 -DIN_BIBREF")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DYYDEBUG=1")

#add_executable(pbrst-cli statements/pbrst-cli.c ${PARSER_DIR}/pbrst.tab.h "${LEXER_OUT}" "${PARSER_OUT}")

Expand All @@ -47,7 +56,6 @@ SET(PBRST_SRCS
fingerprint-wrapper.cpp fingerprint-wrapper.h
${PARSER_DIR}/pbrst.tab.h "${LEXER_OUT}" "${PARSER_OUT}"
)
endif(PBRST)

add_executable(bibref main.cpp book.cpp book.h books.cpp books.h fingerprint.cpp fingerprint.h cli.cpp cli.h psalmsinfo.cpp psalmsinfo.h
${PBRST_SRCS}
Expand All @@ -63,16 +71,25 @@ if(APPLE)
set(sword_LIBRARIES_folder "-L/usr/local/lib") # this is hardcoded (via configure/make install), FIXME
endif()

target_link_libraries(bibref
${sword_LIBRARIES} ${sword_LIBRARIES_folder} ${Boost_LIBRARIES} ${readline_LIBRARIES}
)

if(EMSCRIPTEN)
target_link_libraries(bibref ${SWORD_LIB} ${Boost_LIBRARIES})
target_link_options(bibref PUBLIC -sSINGLE_FILE -sUSE_BOOST_HEADERS -sALLOW_MEMORY_GROWTH -O3 -fexceptions)
target_link_options(bibref PUBLIC "SHELL:
--preload-file '$ENV{HOME}/.sword@/'")
target_link_options(bibref PUBLIC "SHELL:
--preload-file '${BIBREF_ADDBOOKS_CACHE_FOLDER}@/bibref-addbooks-cache'")
target_link_options(bibref PUBLIC -sEXTRA_EXPORTED_RUNTIME_METHODS=['cwrap'] -sMODULARIZE -sEXPORT_NAME=bibref)
else()
target_link_libraries(bibref ${sword_LIBRARIES} ${sword_LIBRARIES_folder} ${Boost_LIBRARIES} ${readline_LIBRARIES})
endif(EMSCRIPTEN)

install(
CODE " set(ENV{SWORD_PATH} \"$ENV{HOME}/.sword\") "
# Download and install LXX and SBLGNT via CrossWire...
## Now we disable this because LXX was updated to version 3.0 and its versification ("LXX") differs from version 2.5 ("KJV"),
## so we want to avoid installing the new version for the moment. Instead, we use the bundled versions...
## In fact, now (February 2025) the bundled version contains LXX version 3.0, but
## it is simpler to maintain a ZIP bundle than managing the modules via installmgr.
## CODE " execute_process (COMMAND bash -c \"test -d \\\"$SWORD_PATH/mods.d\\\" || (mkdir -p \\\"$SWORD_PATH/mods.d\\\"; echo yes | installmgr -init)\") "
## CODE " execute_process (COMMAND bash -c \"installmgr -s | grep \\\"\\\\[CrossWire\\\\]\\\" || echo yes | installmgr -sc\") "
## CODE " execute_process (COMMAND bash -c \"echo yes | installmgr -r CrossWire\") "
Expand Down
31 changes: 21 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@
# in the cmake configuration are important, otherwise the SWORD utilities
# and examples will also be built, but some of them will eventually fail
# and the library will not be copied to the official emsdk folder.
# (In that case you need to do that manually.)
# (In that case you need to do that manually.) There will be no shared library created.
#
# 3. Step 2 will make sure that libsword.a is visible for the rest of the process,
# but the first LDFLAGS setting makes sure that one can extend the search path
# by the scope of the ".." folder.
# 3. Step 2 will make sure that libsword.a is visible for the rest of the process.
# Unfortunately, since static libraries are not available published properly by
# the SWORD library setup, we still have to work around manually that
# the first LDFLAGS setting extends the scope to find the library also under the ".." folder.
#
# 4. Issue "emmake make" in the current directory.
# 4. Create symlinks in this folder to the files statements/{pbrst.c,pbrst.tab.c,pbrst.tab.h}.
# These files will be present only if you successfully compile the native program above.
# Issue then "emmake make" in the current directory.
#
# See also the GitHub actions in the .github/ folder for more information on the
# steps above. They may be somewhat different, but hopefully still working.
Expand Down Expand Up @@ -67,12 +70,16 @@ TARGET_HTML ?= bibref.html

BUILD_DIR ?= ./wasm-build

SRCS := book.cpp books.cpp cli.cpp fingerprint.cpp main.cpp psalmsinfo.cpp
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
CXX_SRCS := book.cpp books.cpp cli.cpp fingerprint.cpp main.cpp psalmsinfo.cpp \
books-wrapper.cpp fingerprint-wrapper.cpp
CXX_OBJS := $(CXX_SRCS:%=$(BUILD_DIR)/%.o)
C_SRCS := pbrst.tab.c pbrst.c
C_OBJS := $(C_SRCS:%=$(BUILD_DIR)/%.o)
DOXS := book.dox books.dox cli.dox fingerprint.dox main.dox psalmsinfo.dox

CPPFLAGS += -I/usr/include/sword -s USE_BOOST_HEADERS=1
CPPFLAGS += -I/usr/include/sword -s USE_BOOST_HEADERS=1 -DYYDEBUG=1

CFLAGS := -s EXPORTED_FUNCTIONS=[_bibref_wasm,_bibref_wasm_vocabulary] -s EXTRA_EXPORTED_RUNTIME_METHODS=['cwrap'] -fexceptions
CXXFLAGS := -s EXPORTED_FUNCTIONS=[_bibref_wasm,_bibref_wasm_vocabulary] -s EXTRA_EXPORTED_RUNTIME_METHODS=['cwrap'] -fexceptions

BIBREF_NATIVE_FOLDER := $(shell find . -name bibref -executable -printf "%h\n" | sort | head -1)
Expand All @@ -87,15 +94,19 @@ ifeq ($(TARGET_HTML),bibref.js)
LDFLAGS += -s MODULARIZE=1 -s EXPORT_NAME=bibref
endif

$(BUILD_DIR)/$(TARGET_HTML): $(OBJS)
$(BUILD_DIR)/$(TARGET_HTML): $(CXX_OBJS) $(C_OBJS)
$(MKDIR_P) $(dir $@)
echo addbooks | $(BIBREF_NATIVE_FOLDER)/bibref # Make sure bibref generates its cache.
$(CXX) $(OBJS) -o $@ $(LDFLAGS)
$(LD) $(CXX_OBJS) $(C_OBJS) -o $@ $(LDFLAGS)

$(BUILD_DIR)/%.cpp.o: %.cpp
$(MKDIR_P) $(dir $@)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@

$(BUILD_DIR)/%.c.o: %.c
$(MKDIR_P) $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

#######################################################################################################
# Documentation related code

Expand Down
20 changes: 2 additions & 18 deletions cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
#include <algorithm>
#include <vector>

#ifdef WITH_PBRST
extern "C" char* brst_scan_string(char *string, int correct_raw, int correct_differ,
int correct_cover, int correct_versification, int show_dump);
// #include "statements/pbrst.tab.h" // use flex/bison parser for bibref statements (brst)
#include "pbrst.tab.h" // the statements folder must be included among the folders
#endif

using namespace std;

Expand Down Expand Up @@ -75,10 +72,8 @@ string tokensCmd = "tokens";
string searchCmd = "search";
string quitCmd = "quit";
string helpCmd = "help";
#ifdef WITH_PBRST
string statementCmd = "statement";
string statementCmd2 = "Statement";
#endif

string errorNotRecognized = "Sorry, the command you entered was not recognized or its syntax is invalid.";
string errorTextIncomplete = "Either " + textCmd + "1 or " + textCmd + "2 must be used.";
Expand Down Expand Up @@ -111,11 +106,8 @@ vector<string> commands {addbooksCmd, compareCmd + "12", jaccardCmd + "12",
minuniqueCmd + "1", latintextCmd + "1", latintextCmd + "2",
extendCmd, getrefsCmd, lookupCmd, maxresultsCmd, sqlCmd, psalminfoCmd,
rawCmd, rawCmd + "1", rawCmd + "2",
printCmd + "1", printCmd + "2", colorsCmd, tokensCmd, searchCmd
#ifdef WITH_PBRST
, statementCmd
#endif
};
printCmd + "1", printCmd + "2", colorsCmd, tokensCmd, searchCmd, statementCmd
};
vector<string> vocabulary = commands;

void add_vocabulary_item(string item) {
Expand Down Expand Up @@ -261,10 +253,8 @@ string getHelp(const string &key)
"Tokenization is done via Strong's numbers.",
"* `help` *command*: Show some hints on usage of *command*, or get general help if no "
"parameter is given.",
#ifdef WITH_PBRST
"* `statement` ...: Analyze the given statement, see https://matek.hu/zoltan/blog-20250102.php "
"for some explanations.",
#endif
"* `quit`: Exit program."};
string retval;
for (int i = 0; i < helpStr.size(); i++) {
Expand Down Expand Up @@ -851,7 +841,6 @@ void processGetrefsCmd(string input) {
info("Finished"); // Success!
}

#ifdef WITH_PBRST
void processStatementCmd(string input) {
char *output = brst_scan_string((char*)input.c_str(), 0, 0, 0, 0, 0);
string output_s(output);
Expand All @@ -865,7 +854,6 @@ void processStatementCmd(string input) {
}
info("Finished"); // Success!
}
#endif

string cli_process(char *buf) {
string rawinput(buf); // Convert the input to string.
Expand Down Expand Up @@ -925,10 +913,8 @@ string cli_process(char *buf) {
processExtendCmd(input);
else if (boost::starts_with(input, getrefsCmd))
processGetrefsCmd(input);
#ifdef WITH_PBRST
else if (boost::starts_with(input, statementCmd) || boost::starts_with(input, statementCmd2))
processStatementCmd(input);
#endif
// If the input is not recognized, we show an error...
else if (input.length() != 0) // unless there was no input at all
error(errorNotRecognized);
Expand Down Expand Up @@ -999,14 +985,12 @@ void cli(const char *input_prepend, const char *output_prepend, bool addbooks, b
line = string(bufline);
// Handle multiline inputs (for the statement command)...
boost::algorithm::trim(line); // Trim the input.
#ifdef WITH_PBRST
if (!multiline && (boost::starts_with(line, statementCmd) || boost::starts_with(line, statementCmd2))) {
multiline = true;
}
if (multiline && boost::ends_with(line, ".")) {
multiline = false;
}
#endif // WITH_PBRST
strcat(buf, bufline);
if (!multiline) {
cli_process(buf); // Process the input.
Expand Down
9 changes: 1 addition & 8 deletions qt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
cmake_minimum_required(VERSION 3.16)
project(bibref-qt LANGUAGES CXX C)

option(PBRST "Include the brst parser" OFF)

find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Concurrent SvgWidgets)

find_package(PkgConfig REQUIRED)
Expand Down Expand Up @@ -50,9 +48,6 @@ set(CMAKE_AUTOUIC ON)
add_definitions(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}"
-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}")

if(PBRST)
add_compile_definitions(WITH_PBRST)

set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}")
find_package(FLEX 2.6 REQUIRED)
find_package(BISON 3.0 REQUIRED)
Expand All @@ -66,16 +61,14 @@ bison_target(PARSER "${CMAKE_CURRENT_SOURCE_DIR}/../statements/pbrst.y" "${PARSE
add_flex_bison_dependency(LEXER PARSER)

include_directories(${PARSER_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/..")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DYYDEBUG=1 -DIN_BIBREF")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DYYDEBUG=1")

SET(PBRST_SRCS
books-wrapper.cpp books-wrapper.h
fingerprint-wrapper.cpp fingerprint-wrapper.h
"${LEXER_OUT}" "${PARSER_OUT}"
)

endif(PBRST)

# set the Application icon, the first line is the property added to Info.plist
set(MACOSX_BUNDLE_ICON_FILE bibref-qt.icns)
set(bibref_qt_ICON ${CMAKE_CURRENT_SOURCE_DIR}/logo-Psalm40-256.icns)
Expand Down
9 changes: 0 additions & 9 deletions qt/statementwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <QtWidgets>
#include <iostream>

#ifdef WITH_PBRST
#include <string>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/predicate.hpp>
Expand All @@ -15,7 +14,6 @@ extern "C" char* brst_scan_string(char *string, int correct_raw, int correct_dif
#include "pbrst.tab.h" // the statements folder must be included among the folders

using namespace std;
#endif

StatementWindow::StatementWindow(QWidget *parent)
: QMainWindow(parent)
Expand Down Expand Up @@ -123,7 +121,6 @@ void StatementWindow::setupFileMenu()

void StatementWindow::parse()
{
#ifdef WITH_PBRST
char* output = brst_scan_string((char*)editor->toPlainText().toStdString().c_str(), 0, 0, 0, 0, 0);
string output_s(output);
vector<string> statementAnalysis;
Expand Down Expand Up @@ -195,30 +192,24 @@ void StatementWindow::parse()
link += QUrl::toPercentEncoding(QString::fromStdString(graphviz_input));
QDesktopServices::openUrl(QUrl(link));
}

#endif
}

void StatementWindow::showSvg()
{
#ifdef WITH_PBRST
auto vwindow = new VisualizeWindow(this, graphviz_input);
// vwindow->resize(600, 400);
vwindow->show();
vwindow->setWindowIcon(QIcon::fromTheme("emblem-photos"));
vwindow->setWindowTitle(tr("Visualize"));
#endif // WITH_PBRST
}

void StatementWindow::setupProveMenu()
{
#ifdef WITH_PBRST
QMenu *proveMenu = new QMenu(tr("&Prove"), this);
menuBar()->addMenu(proveMenu);

proveMenu->addAction(QIcon::fromTheme("tools-check-spelling"), tr("&Parse"), QKeySequence::Forward,
this, &StatementWindow::parse);
#endif // WITH_PBRST
}

void StatementWindow::setupHelpMenu()
Expand Down
Loading

0 comments on commit eac4c92

Please sign in to comment.