From 0ef248b4afb4ffaad1082fada5260474eed40c88 Mon Sep 17 00:00:00 2001 From: Frank Lin Date: Sat, 11 Jul 2026 13:30:18 -0700 Subject: [PATCH 1/7] Revert "Temporarily roll back npm version bump to 1.4.0" This reverts commit 70b45211802e907040ff06b53a2de6aefed64892 and bumps version to 1.4.1 again. --- NEWS.md | 9 +++ package-lock.json | 71 +++++-------------- package.json | 11 +-- plugins/jieba/node/package.json | 11 +-- .../jieba/node/scripts/verify-main-package.js | 1 + scripts/verify-node-main-package.js | 1 + 6 files changed, 41 insertions(+), 63 deletions(-) diff --git a/NEWS.md b/NEWS.md index 075af578d..d6250b2fe 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,14 @@ # Change History of OpenCC +## Version 1.4.1 + +* **發佈重點**:修復 `opencc` npm 套件在沒有預編譯二進制的平台(如 Intel Mac)上退回源碼編譯時,因源碼包缺少檔案而安裝失敗的問題;並新增 darwin-x64(Intel Mac)預編譯 npm 套件。 +* **Node.js**: + * 修復 npm 源碼包缺少 `src/ConfigBasedConverter.hpp`、`src/PipelineConverter.cpp/.hpp`、`src/SingleStageConverter.cpp/.hpp`、`src/opencc_config_schema.inc` 六個編譯所需檔案,導致 `npm install` 源碼編譯失敗([#1409](https://github.com/BYVoid/OpenCC/issues/1409))。 + * 新增 `@opencc/opencc-darwin-x64` 與 `@opencc/opencc-jieba-darwin-x64` 預編譯套件,Intel Mac 不再需要源碼編譯。 + * `prepack` 驗證腳本新增 gyp 源碼與 `#include` 閉包檢查,確保源碼編譯所需的所有檔案都在 npm 包的 `files` 白名單內,防止同類問題再次發生。 + * CI 新增「從 `npm pack` 產出的 tarball 進行源碼編譯並安裝」的測試(ubuntu / macOS ARM / macOS Intel),覆蓋無預編譯二進制平台的實際安裝路徑。 + ## Version 1.4.0 2026年7月1日 diff --git a/package-lock.json b/package-lock.json index 8898f220c..114b73f53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "opencc", - "version": "1.4.0", + "version": "1.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opencc", - "version": "1.4.0", + "version": "1.4.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -25,10 +25,11 @@ "node": ">=20.17" }, "optionalDependencies": { - "@opencc/opencc-darwin-arm64": "1.4.0", - "@opencc/opencc-linux-arm64": "1.4.0", - "@opencc/opencc-linux-x64": "1.4.0", - "@opencc/opencc-win32-x64": "1.4.0" + "@opencc/opencc-darwin-arm64": "1.4.1", + "@opencc/opencc-darwin-x64": "1.4.1", + "@opencc/opencc-linux-arm64": "1.4.1", + "@opencc/opencc-linux-x64": "1.4.1", + "@opencc/opencc-win32-x64": "1.4.1" } }, "node_modules/@apidevtools/json-schema-ref-parser": { @@ -69,56 +70,19 @@ "license": "MIT" }, "node_modules/@opencc/opencc-darwin-arm64": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@opencc/opencc-darwin-arm64/-/opencc-darwin-arm64-1.4.0.tgz", - "integrity": "sha512-yFQJgV7sll3WXG576KxRHg2ITmzEy1h+tbzWLsD+u18Svp0P6KYRd+ywMgmjN7lrLdeEb8De0CjEgfamcZnGjw==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ] + "optional": true + }, + "node_modules/@opencc/opencc-darwin-x64": { + "optional": true }, "node_modules/@opencc/opencc-linux-arm64": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@opencc/opencc-linux-arm64/-/opencc-linux-arm64-1.4.0.tgz", - "integrity": "sha512-QLKcLbKVXkC4AU+cWR9scrOllKd1z1O6yexwqlEJGy67b9hn7FohztK8EY6+tmU6gobTm3P619Cm/o30SxIy/w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ] + "optional": true }, "node_modules/@opencc/opencc-linux-x64": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@opencc/opencc-linux-x64/-/opencc-linux-x64-1.4.0.tgz", - "integrity": "sha512-0Yk3FZNP7gt0hJqTSqE765tPpNpinLPVYzR4PAxmckTdJtpuu5MK9l7hyGcq/+pY1vkx5Pf4ZUhQ0/82tErBHg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ] + "optional": true }, "node_modules/@opencc/opencc-win32-x64": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@opencc/opencc-win32-x64/-/opencc-win32-x64-1.4.0.tgz", - "integrity": "sha512-bVrnFAX2dA4AV1i/u8uqswssEIg3+9OZIBLnF7H0hQ6kUmEZRmsH5iwWNgR2egabRFBVpdkQfHyRrMzwSL2vog==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ] + "optional": true }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -547,6 +511,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -573,9 +538,9 @@ } }, "node_modules/prettier": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.4.tgz", - "integrity": "sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.5.tgz", + "integrity": "sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index 76e3b59f8..5622dae7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencc", - "version": "1.4.0", + "version": "1.4.1", "description": "Conversion between Traditional and Simplified Chinese", "author": "Carbo Kuo ", "license": "Apache-2.0", @@ -159,10 +159,11 @@ "node-gyp-build": "^4.8.4" }, "optionalDependencies": { - "@opencc/opencc-darwin-arm64": "1.4.0", - "@opencc/opencc-linux-arm64": "1.4.0", - "@opencc/opencc-linux-x64": "1.4.0", - "@opencc/opencc-win32-x64": "1.4.0" + "@opencc/opencc-darwin-arm64": "1.4.1", + "@opencc/opencc-darwin-x64": "1.4.1", + "@opencc/opencc-linux-arm64": "1.4.1", + "@opencc/opencc-linux-x64": "1.4.1", + "@opencc/opencc-win32-x64": "1.4.1" }, "overrides": { "brace-expansion": "^2.0.3", diff --git a/plugins/jieba/node/package.json b/plugins/jieba/node/package.json index 6bbde5ea3..94d6f44d2 100644 --- a/plugins/jieba/node/package.json +++ b/plugins/jieba/node/package.json @@ -1,6 +1,6 @@ { "name": "opencc-jieba", - "version": "1.4.0", + "version": "1.4.1", "description": "Jieba segmentation plugin for OpenCC", "author": "Carbo Kuo and OpenCC contributors", "license": "Apache-2.0", @@ -14,10 +14,11 @@ "opencc": ">=1.4.0" }, "optionalDependencies": { - "@opencc/opencc-jieba-darwin-arm64": "1.4.0", - "@opencc/opencc-jieba-linux-arm64": "1.4.0", - "@opencc/opencc-jieba-linux-x64": "1.4.0", - "@opencc/opencc-jieba-win32-x64": "1.4.0" + "@opencc/opencc-jieba-darwin-arm64": "1.4.1", + "@opencc/opencc-jieba-darwin-x64": "1.4.1", + "@opencc/opencc-jieba-linux-arm64": "1.4.1", + "@opencc/opencc-jieba-linux-x64": "1.4.1", + "@opencc/opencc-jieba-win32-x64": "1.4.1" }, "files": [ "index.js", diff --git a/plugins/jieba/node/scripts/verify-main-package.js b/plugins/jieba/node/scripts/verify-main-package.js index bf7cb5363..03603221a 100644 --- a/plugins/jieba/node/scripts/verify-main-package.js +++ b/plugins/jieba/node/scripts/verify-main-package.js @@ -23,6 +23,7 @@ const requiredFiles = [ const expectedOptionalPackages = [ '@opencc/opencc-jieba-darwin-arm64', + '@opencc/opencc-jieba-darwin-x64', '@opencc/opencc-jieba-linux-arm64', '@opencc/opencc-jieba-linux-x64', '@opencc/opencc-jieba-win32-x64', diff --git a/scripts/verify-node-main-package.js b/scripts/verify-node-main-package.js index 742fa9933..28369ad3b 100644 --- a/scripts/verify-node-main-package.js +++ b/scripts/verify-node-main-package.js @@ -25,6 +25,7 @@ const requiredFiles = [ const expectedOptionalPackages = [ '@opencc/opencc-darwin-arm64', + '@opencc/opencc-darwin-x64', '@opencc/opencc-linux-arm64', '@opencc/opencc-linux-x64', '@opencc/opencc-win32-x64', From 818a0160e36fe2d404edb7326863ae6967827265 Mon Sep 17 00:00:00 2001 From: Frank Lin Date: Sat, 11 Jul 2026 15:14:54 -0700 Subject: [PATCH 2/7] Generate merged Jieba dictionary with opencc_dict and remove private build tool Since #1392 opencc_dict supports the cppjieba_utf8 input format, so the CMake and Bazel builds now invoke it directly to produce jieba_dict/jieba_merged.ocd2, and the duplicated opencc_jieba_dict_build_tool (formerly cppjieba_dict) is deleted. Output is byte-identical to the old tool on all three build paths (in-tree CMake, Bazel, standalone plugin build). Standalone plugin builds now locate an installed opencc_dict via find_program (hinted from the found OpenCC package) and fail at configure time with a clear message unless it supports cppjieba_utf8, i.e. OpenCC >= 1.4.1. Debian packaging follows suit: drop the stale usr/bin/cppjieba_dict entry from opencc-jieba.install (the tool is no longer installed) and update SPLIT_PROPOSAL.md to describe the opencc_dict-based flow. --- packaging/debian/SPLIT_PROPOSAL.md | 10 +- packaging/debian/debian/opencc-jieba.install | 1 - plugins/jieba/BUILD.bazel | 15 +- plugins/jieba/CMakeLists.txt | 67 ++-- plugins/jieba/tools/JiebaDictBuildTool.cpp | 306 ------------------- 5 files changed, 47 insertions(+), 352 deletions(-) delete mode 100644 plugins/jieba/tools/JiebaDictBuildTool.cpp diff --git a/packaging/debian/SPLIT_PROPOSAL.md b/packaging/debian/SPLIT_PROPOSAL.md index 38fd1b15b..1a47aa7d9 100644 --- a/packaging/debian/SPLIT_PROPOSAL.md +++ b/packaging/debian/SPLIT_PROPOSAL.md @@ -69,11 +69,11 @@ release artifact for continuity: Depends: `opencc (= ${binary:Version})`, `libopencc-data (>= ${source:Version})`. -`plugins/jieba/CMakeLists.txt` also builds `opencc_jieba_dict_build_tool`, -the offline tool that merges the bundled Jieba dictionaries into -`jieba_dict/jieba_merged.ocd2` at build time. Upstream does not -`install()` this tool, so it is a build dependency only and is not -shipped in `opencc-jieba` (or any package) here either. +The merged Jieba dictionary (`jieba_dict/jieba_merged.ocd2`) is generated +at build time by upstream's own `opencc_dict` tool +(`--from cppjieba_utf8`), which is built in-tree during the package build +and already shipped in the `opencc` binary package; no additional +dictionary tool is built or shipped. Known blocker for a real Debian upload: `plugins/jieba/deps/cppjieba` is a header-only C++ library with **no existing Debian package** to build diff --git a/packaging/debian/debian/opencc-jieba.install b/packaging/debian/debian/opencc-jieba.install index 0c01939c5..91f72b61e 100644 --- a/packaging/debian/debian/opencc-jieba.install +++ b/packaging/debian/debian/opencc-jieba.install @@ -1,4 +1,3 @@ -usr/bin/cppjieba_dict usr/lib/*/opencc/plugins usr/share/opencc/jieba_dict usr/share/opencc/hk2sp_jieba.json diff --git a/plugins/jieba/BUILD.bazel b/plugins/jieba/BUILD.bazel index 99b859d45..e78305f62 100644 --- a/plugins/jieba/BUILD.bazel +++ b/plugins/jieba/BUILD.bazel @@ -75,19 +75,8 @@ genrule( "//plugins/jieba/deps/cppjieba:dict/user.dict.utf8", ], outs = ["jieba_dict/jieba_merged.ocd2"], - cmd = "$(location :opencc_jieba_dict_build_tool) -i $(location //plugins/jieba/deps/cppjieba:dict/jieba.dict.utf8) -i $(location //plugins/jieba/deps/cppjieba:dict/user.dict.utf8) -o $@", - tools = [":opencc_jieba_dict_build_tool"], -) - -cc_binary( - name = "opencc_jieba_dict_build_tool", - srcs = ["tools/JiebaDictBuildTool.cpp"], - deps = [ - "//src:dict_lib", - "//src:dict_entry_lib", - "//src:lexicon_lib", - "//src:marisa_dict_lib", - ], + cmd = "$(location //src/tools:dict_converter) --from cppjieba_utf8 --to ocd2 --input $(location //plugins/jieba/deps/cppjieba:dict/jieba.dict.utf8) --input $(location //plugins/jieba/deps/cppjieba:dict/user.dict.utf8) --output $@", + tools = ["//src/tools:dict_converter"], ) cc_test( diff --git a/plugins/jieba/CMakeLists.txt b/plugins/jieba/CMakeLists.txt index 4b04c38c0..fd70b83b0 100644 --- a/plugins/jieba/CMakeLists.txt +++ b/plugins/jieba/CMakeLists.txt @@ -86,8 +86,6 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) src/JiebaSegmentationPlugin.cpp ) target_link_libraries(opencc_jieba PRIVATE OpenCC::OpenCC) - add_executable(opencc_jieba_dict_build_tool tools/JiebaDictBuildTool.cpp) - target_link_libraries(opencc_jieba_dict_build_tool PRIVATE OpenCC::OpenCC) else() add_library(opencc_jieba SHARED src/JiebaSegmentation.cpp @@ -99,12 +97,6 @@ else() ${PROJECT_BINARY_DIR}/src ) target_link_libraries(opencc_jieba PRIVATE libopencc) - add_executable(opencc_jieba_dict_build_tool tools/JiebaDictBuildTool.cpp) - target_include_directories(opencc_jieba_dict_build_tool PRIVATE - ${PROJECT_SOURCE_DIR}/src - ${PROJECT_BINARY_DIR}/src - ) - target_link_libraries(opencc_jieba_dict_build_tool PRIVATE libopencc) endif() target_compile_definitions(opencc_jieba PRIVATE OPENCC_PLUGIN_BUILD) @@ -155,22 +147,43 @@ if (WIN32 AND _opencc_target_arch AND _opencc_host_arch) endif() endif() -if (WIN32 AND OPENCC_CAN_RUN_CPPJIEBA_DICT) +if (OPENCC_CAN_RUN_CPPJIEBA_DICT) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) - set(_opencc_runtime_target OpenCC::OpenCC) + # Standalone plugin build: use the opencc_dict installed alongside the + # OpenCC package found by find_package. Merging the bundled Jieba + # dictionaries requires the cppjieba_utf8 input format (OpenCC >= 1.4.1). + find_program(OPENCC_DICT_EXECUTABLE opencc_dict + HINTS "${_opencc_install_prefix_hint}/bin") + if (NOT OPENCC_DICT_EXECUTABLE) + message(FATAL_ERROR + "opencc_dict not found. Building the merged Jieba dictionary requires " + "the opencc_dict tool from OpenCC 1.4.1 or later.") + endif() + execute_process( + COMMAND "${OPENCC_DICT_EXECUTABLE}" --help + OUTPUT_VARIABLE _opencc_dict_help + ERROR_VARIABLE _opencc_dict_help_err + ) + if (NOT "${_opencc_dict_help}${_opencc_dict_help_err}" MATCHES + "cppjieba_utf8") + message(FATAL_ERROR + "${OPENCC_DICT_EXECUTABLE} does not support the cppjieba_utf8 input " + "format. OpenCC 1.4.1 or later is required.") + endif() + set(OPENCC_DICT_COMMAND "${OPENCC_DICT_EXECUTABLE}") + set(OPENCC_DICT_TARGET_DEPENDS) else() - set(_opencc_runtime_target libopencc) + set(OPENCC_DICT_COMMAND opencc_dict) + set(OPENCC_DICT_TARGET_DEPENDS opencc_dict) endif() +endif() - add_custom_target( - copy_opencc_to_jieba_dict_build_tool - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - $ - DEPENDS opencc_jieba_dict_build_tool - COMMENT "Copying OpenCC runtime to directory of opencc_jieba_dict_build_tool" - ) - set(JIEBA_MERGED_DICT_WIN32_DEPENDS copy_opencc_to_jieba_dict_build_tool) +if (WIN32 AND OPENCC_CAN_RUN_CPPJIEBA_DICT AND + NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + # opencc_dict in the build tree needs libopencc next to it to run; data/ + # already defines this copy target for its own dictionary generation. An + # installed opencc_dict (standalone build) ships next to its runtime. + set(JIEBA_MERGED_DICT_WIN32_DEPENDS copy_libopencc_to_dir_of_opencc_dict) else() set(JIEBA_MERGED_DICT_WIN32_DEPENDS) endif() @@ -179,13 +192,15 @@ if (OPENCC_CAN_RUN_CPPJIEBA_DICT) add_custom_command( OUTPUT "${JIEBA_MERGED_DICT}" COMMAND ${CMAKE_COMMAND} -E make_directory "${JIEBA_MERGED_DICT_DIR}" - COMMAND $ - -i "${CMAKE_CURRENT_SOURCE_DIR}/deps/cppjieba/dict/jieba.dict.utf8" - -i "${CMAKE_CURRENT_SOURCE_DIR}/deps/cppjieba/dict/user.dict.utf8" - -o "${JIEBA_MERGED_DICT}" + COMMAND ${OPENCC_DICT_COMMAND} + --from cppjieba_utf8 + --to ocd2 + --input "${CMAKE_CURRENT_SOURCE_DIR}/deps/cppjieba/dict/jieba.dict.utf8" + --input "${CMAKE_CURRENT_SOURCE_DIR}/deps/cppjieba/dict/user.dict.utf8" + --output "${JIEBA_MERGED_DICT}" DEPENDS ${JIEBA_MERGED_DICT_WIN32_DEPENDS} - opencc_jieba_dict_build_tool + ${OPENCC_DICT_TARGET_DEPENDS} "${CMAKE_CURRENT_SOURCE_DIR}/deps/cppjieba/dict/jieba.dict.utf8" "${CMAKE_CURRENT_SOURCE_DIR}/deps/cppjieba/dict/user.dict.utf8" VERBATIM @@ -206,8 +221,6 @@ if (WIN32) endif() if (_opencc_target_type STREQUAL "STATIC_LIBRARY") target_compile_definitions(opencc_jieba PRIVATE Opencc_BUILT_AS_STATIC) - target_compile_definitions(opencc_jieba_dict_build_tool PRIVATE - Opencc_BUILT_AS_STATIC) endif() endif() diff --git a/plugins/jieba/tools/JiebaDictBuildTool.cpp b/plugins/jieba/tools/JiebaDictBuildTool.cpp deleted file mode 100644 index 18b7edfb0..000000000 --- a/plugins/jieba/tools/JiebaDictBuildTool.cpp +++ /dev/null @@ -1,306 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__has_include) -#if __has_include("src/Dict.hpp") -#include "src/Dict.hpp" -#include "src/DictEntry.hpp" -#include "src/Lexicon.hpp" -#include "src/MarisaDict.hpp" -#include "src/SerializableDict.hpp" -#elif __has_include("Dict.hpp") -#include "Dict.hpp" -#include "DictEntry.hpp" -#include "Lexicon.hpp" -#include "MarisaDict.hpp" -#include "SerializableDict.hpp" -#elif __has_include() -#include -#include -#include -#include -#include -#else -#error "Unable to locate OpenCC headers" -#endif -#else -#include "Dict.hpp" -#include "DictEntry.hpp" -#include "Lexicon.hpp" -#include "MarisaDict.hpp" -#include "SerializableDict.hpp" -#endif - -namespace { - -using opencc::Dict; -using opencc::DictEntry; -using opencc::DictEntryFactory; -using opencc::Lexicon; -using opencc::LexiconPtr; -using opencc::MarisaDict; -using opencc::MarisaDictPtr; -using opencc::Optional; -using opencc::SerializableDict; - -void PrintUsage(std::ostream& os) { - os << "Usage: opencc_jieba_dict_build_tool -i [-i ...] " - "-o " - << std::endl - << " -i Input dictionary file. The first -i is parsed as" - << std::endl - << " the base jieba dict; later -i files are parsed as" - << std::endl - << " user dict overlays." << std::endl - << " -o Output OpenCC marisa dictionary file." - << std::endl; -} - -std::vector SplitWhitespace(const std::string& line) { - std::vector tokens; - std::istringstream iss(line); - std::string token; - while (iss >> token) { - tokens.push_back(token); - } - return tokens; -} - -bool IsCommentOrEmpty(const std::string& line) { - if (line.empty()) { - return true; - } - for (size_t i = 0; i < line.size(); ++i) { - const unsigned char ch = static_cast(line[i]); - if (!std::isspace(ch)) { - return false; - } - } - return true; -} - -std::vector -ParseBaseDictValues(const std::vector& tokens, size_t lineNumber) { - if (tokens.size() != 3) { - throw std::runtime_error("invalid base dict line " + - std::to_string(lineNumber)); - } - return std::vector{tokens[1], tokens[2], "base"}; -} - -std::vector -ParseUserDictValues(const std::vector& tokens, size_t lineNumber) { - if (tokens.empty() || tokens.size() > 3) { - throw std::runtime_error("invalid user dict line " + - std::to_string(lineNumber)); - } - if (tokens.size() == 1) { - return std::vector{"", "", "user_default"}; - } - if (tokens.size() == 2) { - return std::vector{"", tokens[1], "user_default"}; - } - return std::vector{tokens[1], tokens[2], "user_freq"}; -} - -class LexiconDict : public Dict { -public: - explicit LexiconDict(std::vector> entries) - : lexicon_(new Lexicon(std::move(entries))), maxLength_(0) { - for (size_t i = 0; i < lexicon_->Length(); ++i) { - const DictEntry* entry = lexicon_->At(i); - if (entry->KeyLength() > maxLength_) { - maxLength_ = entry->KeyLength(); - } - } - } - - Optional Match(const char* word, size_t len) const override { - const std::string needle(word, len); - for (size_t i = 0; i < lexicon_->Length(); ++i) { - const DictEntry* entry = lexicon_->At(i); - if (entry->Key() == needle) { - return Optional(entry); - } - } - return Optional::Null(); - } - - Optional MatchPrefix(const char* word, - size_t len) const override { - const size_t cappedLen = len < maxLength_ ? len : maxLength_; - const DictEntry* best = nullptr; - size_t bestLength = 0; - for (size_t i = 0; i < lexicon_->Length(); ++i) { - const DictEntry* entry = lexicon_->At(i); - const size_t entryLength = entry->KeyLength(); - if (entryLength > cappedLen || entryLength <= bestLength) { - continue; - } - if (std::string(word, entryLength) == entry->Key()) { - best = entry; - bestLength = entryLength; - } - } - if (best == nullptr) { - return Optional::Null(); - } - return Optional(best); - } - - std::vector MatchAllPrefixes(const char* word, - size_t len) const override { - const size_t cappedLen = len < maxLength_ ? len : maxLength_; - std::vector matches; - for (size_t i = 0; i < lexicon_->Length(); ++i) { - const DictEntry* entry = lexicon_->At(i); - const size_t entryLength = entry->KeyLength(); - if (entryLength > cappedLen) { - continue; - } - if (std::string(word, entryLength) == entry->Key()) { - matches.push_back(entry); - } - } - return matches; - } - - size_t KeyMaxLength() const override { return maxLength_; } - - LexiconPtr GetLexicon() const override { return lexicon_; } - -private: - LexiconPtr lexicon_; - size_t maxLength_; -}; - -void LoadBaseDict(const std::string& path, - std::map>& entries) { - std::ifstream ifs(path.c_str()); - if (!ifs.is_open()) { - throw std::runtime_error("failed to open base dict: " + path); - } - - std::string line; - size_t lineNumber = 0; - while (std::getline(ifs, line)) { - ++lineNumber; - if (IsCommentOrEmpty(line)) { - continue; - } - const std::vector tokens = SplitWhitespace(line); - entries[tokens[0]] = ParseBaseDictValues(tokens, lineNumber); - } -} - -void LoadUserDict(const std::string& path, - std::map>& entries) { - std::ifstream ifs(path.c_str()); - if (!ifs.is_open()) { - throw std::runtime_error("failed to open user dict: " + path); - } - - std::string line; - size_t lineNumber = 0; - while (std::getline(ifs, line)) { - ++lineNumber; - if (IsCommentOrEmpty(line)) { - continue; - } - const std::vector tokens = SplitWhitespace(line); - if (tokens.empty()) { - continue; - } - entries[tokens[0]] = ParseUserDictValues(tokens, lineNumber); - } -} - -void WriteOcd2(const std::map>& entries, - const std::string& outputPath) { - std::vector> lexiconEntries; - lexiconEntries.reserve(entries.size()); - for (const auto& entry : entries) { - lexiconEntries.push_back(std::unique_ptr( - DictEntryFactory::New(entry.first, entry.second))); - } - - LexiconDict dict(std::move(lexiconEntries)); - MarisaDictPtr marisaDict = MarisaDict::NewFromDict(dict); - static_cast(*marisaDict).SerializeToFile(outputPath); -} - -} // namespace - -int main(int argc, char** argv) { - std::vector inputPaths; - std::string outputPath; - - for (int i = 1; i < argc; ++i) { - const std::string arg = argv[i]; - if (arg == "-i") { - if (i + 1 >= argc) { - std::cerr << "opencc_jieba_dict_build_tool: missing value after -i" - << std::endl; - PrintUsage(std::cerr); - return 1; - } - inputPaths.push_back(argv[++i]); - continue; - } - if (arg == "-o") { - if (i + 1 >= argc) { - std::cerr << "opencc_jieba_dict_build_tool: missing value after -o" - << std::endl; - PrintUsage(std::cerr); - return 1; - } - if (!outputPath.empty()) { - std::cerr << "opencc_jieba_dict_build_tool: exactly one -o is required" - << std::endl; - PrintUsage(std::cerr); - return 1; - } - outputPath = argv[++i]; - continue; - } - - std::cerr << "opencc_jieba_dict_build_tool: unknown argument: " << arg - << std::endl; - PrintUsage(std::cerr); - return 1; - } - - if (inputPaths.empty()) { - std::cerr << "opencc_jieba_dict_build_tool: at least one -i is required" - << std::endl; - PrintUsage(std::cerr); - return 1; - } - if (outputPath.empty()) { - std::cerr << "opencc_jieba_dict_build_tool: exactly one -o is required" - << std::endl; - PrintUsage(std::cerr); - return 1; - } - - try { - std::map> entries; - LoadBaseDict(inputPaths.front(), entries); - for (size_t i = 1; i < inputPaths.size(); ++i) { - LoadUserDict(inputPaths[i], entries); - } - WriteOcd2(entries, outputPath); - } catch (const std::exception& e) { - std::cerr << "opencc_jieba_dict_build_tool: " << e.what() << std::endl; - return 1; - } - - return 0; -} From 6a5d1390494b67b7ec3fac7aeaffd4b9318bf6eb Mon Sep 17 00:00:00 2001 From: Frank Lin Date: Sat, 11 Jul 2026 15:15:05 -0700 Subject: [PATCH 3/7] Finalize 1.4.1 release metadata and notes Complete the 1.4.1 NEWS entry with the release date and all changes since ver.1.4.0 (dictionary fixes, word-size-independent OCD output, Node inline config and schema-generated types, Bazel-built Node release binaries, Debian packaging rework, librime compatibility tests), and note that the node-gyp source fallback is planned for removal in favor of Bazel-only Node builds (also documented in node/PUBLISHING.md). Update README prebuilt binary links to 1.4.1 with a release-focus note, and bump remaining build-time version strings (node/BUILD.bazel, node/global.gypi, setup.py fallback, Windows Zig build scripts) to 1.4.1. --- NEWS.md | 32 ++++++++++++++++++++++++++++--- README.md | 11 ++++++----- node/BUILD.bazel | 2 +- node/PUBLISHING.md | 3 ++- node/global.gypi | 2 +- scripts/build-cli-windows-zig.sh | 2 +- scripts/build-node-windows-zig.sh | 2 +- setup.py | 2 +- 8 files changed, 42 insertions(+), 14 deletions(-) diff --git a/NEWS.md b/NEWS.md index d6250b2fe..fa6a2159e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,12 +2,38 @@ ## Version 1.4.1 -* **發佈重點**:修復 `opencc` npm 套件在沒有預編譯二進制的平台(如 Intel Mac)上退回源碼編譯時,因源碼包缺少檔案而安裝失敗的問題;並新增 darwin-x64(Intel Mac)預編譯 npm 套件。 +2026年7月11日 + +* **發佈重點**:修復 `opencc` npm 套件在沒有預編譯二進制的平台(如 Intel Mac)上退回源碼編譯時,因源碼包缺少檔案而安裝失敗的問題,並新增 darwin-x64(Intel Mac)預編譯 npm 套件;另包含一批詞庫修正、`.ocd` 字典跨平台輸出修復與 Debian 打包流程重建。C++ ABI 與 1.4.0 相同(SOVERSION 1.4),下游程式無需重新鏈結。 +* **詞庫更新**: + * 修正「托 / 託」候選順序:`s2t` 中 `托` 預設保留不轉換(如 `托着`、`茶托`、人名音譯),並補充「託」委託義的詞組轉換([#1405](https://github.com/BYVoid/OpenCC/pull/1405))。 + * 依《通用規範漢字表》與《現代漢語詞典》修正「牴 → 抵」,以及「復 / 複 / 覆」相關轉換([#758](https://github.com/BYVoid/OpenCC/pull/758))。 + * 修正「黄粱美梦」相關轉換:不再輸出「黃樑美夢」,並將 `STPhrases.txt` 中誤作「黄梁」的詞條統一為「黄粱」([#1408](https://github.com/BYVoid/OpenCC/pull/1408), [#1410](https://github.com/BYVoid/OpenCC/pull/1410))。 + * `t2s` 新增「遶 → 绕」轉換([#1399](https://github.com/BYVoid/OpenCC/pull/1399));`t2s` 中保留簡體字形「坏」不再誤轉([#1391](https://github.com/BYVoid/OpenCC/pull/1391))。 + * 新增書法家「梁昇卿」人名詞條([#1402](https://github.com/BYVoid/OpenCC/pull/1402));新增香港地區詞「舒芙蕾 / 梳芙厘」(soufflé)([#1387](https://github.com/BYVoid/OpenCC/pull/1387))。 + * 日文字體:補充 `JPShinjitaiCharacters` 缺失的 11 個新字體字元(依安岡孝一「人名用漢字の新字旧字」),以相容性自映射收錄並用 `@reverse-prefer` 修正 `t2jp` 反向優先序([#1394](https://github.com/BYVoid/OpenCC/pull/1394))。 +* **`.ocd` 字典格式 / 字典工具**: + * `BinaryDict` 序列化改為固定寬度(uint32)欄位,使 32-bit 與 64-bit 構建寫出的 `.ocd` 位元組一致;讀取端自動偵測舊版 64-bit 佈局,舊檔案仍可在任何平台載入([#1414](https://github.com/BYVoid/OpenCC/pull/1414))。 + * CMake 新增 `OPENCC_DICT_FORMAT` 選項(`ocd2` / `text` / `ocd`),可選擇構建輸出的字典格式,配置 JSON 隨之改寫([#1396](https://github.com/BYVoid/OpenCC/pull/1396))。 + * `opencc_dict` 整合 cppjieba 字典轉換(新增 `cppjieba_utf8` 輸入格式),取代並停止安裝原 `cppjieba_dict` 工具([#1392](https://github.com/BYVoid/OpenCC/pull/1392));CMake / Bazel 構建流程進一步改為直接以 `opencc_dict` 生成 jieba 合併詞典並移除私有構建工具,獨立構建 jieba 插件時需系統安裝 OpenCC ≥ 1.4.1 的 `opencc_dict`。 + * vendored `darts-clone` 改為從 BCR 引入 `0.32h.bcr.1`,移除本地補丁([#1386](https://github.com/BYVoid/OpenCC/pull/1386), [#1401](https://github.com/BYVoid/OpenCC/pull/1401))。 * **Node.js**: - * 修復 npm 源碼包缺少 `src/ConfigBasedConverter.hpp`、`src/PipelineConverter.cpp/.hpp`、`src/SingleStageConverter.cpp/.hpp`、`src/opencc_config_schema.inc` 六個編譯所需檔案,導致 `npm install` 源碼編譯失敗([#1409](https://github.com/BYVoid/OpenCC/issues/1409))。 - * 新增 `@opencc/opencc-darwin-x64` 與 `@opencc/opencc-jieba-darwin-x64` 預編譯套件,Intel Mac 不再需要源碼編譯。 + * 修復 npm 源碼包缺少 `src/ConfigBasedConverter.hpp`、`src/PipelineConverter.cpp/.hpp`、`src/SingleStageConverter.cpp/.hpp`、`src/opencc_config_schema.inc` 六個編譯所需檔案,導致 `npm install` 源碼編譯失敗([#1409](https://github.com/BYVoid/OpenCC/issues/1409), [#1411](https://github.com/BYVoid/OpenCC/pull/1411))。 + * 新增 `@opencc/opencc-darwin-x64` 與 `@opencc/opencc-jieba-darwin-x64` 預編譯套件,Intel Mac 不再需要源碼編譯([#1411](https://github.com/BYVoid/OpenCC/pull/1411))。 * `prepack` 驗證腳本新增 gyp 源碼與 `#include` 閉包檢查,確保源碼編譯所需的所有檔案都在 npm 包的 `files` 白名單內,防止同類問題再次發生。 * CI 新增「從 `npm pack` 產出的 tarball 進行源碼編譯並安裝」的測試(ubuntu / macOS ARM / macOS Intel),覆蓋無預編譯二進制平台的實際安裝路徑。 + * JavaScript API 支援以 inline config 物件建立轉換器,保留原有字串配置行為;並覆蓋 bundled assets、自定義配置目錄與 tofu-risk 過濾的測試([#1412](https://github.com/BYVoid/OpenCC/pull/1412))。 + * `OpenCCConfig` TypeScript 型別改由 JSON schema 自動生成,取代原本寬鬆的 `Record` 型別([#1413](https://github.com/BYVoid/OpenCC/pull/1413))。 + * Node 預編譯二進制(`@opencc/opencc-*` scoped 套件)改用 Bazel 構建發佈,`npm run prebuild`(prebuildify / node-gyp)不再是官方發佈二進制的構建方式;Bazel 不支援的平台從此不再提供官方預編譯二進制,在這些平台上 `npm install` 目前仍會退回 node-gyp 源碼編譯,但此 fallback(`binding.gyp`)已計劃在後續版本中移除,屆時 Node 構建將統一使用 Bazel([#1416](https://github.com/BYVoid/OpenCC/pull/1416))。 + * 重寫 Node demo 範例([commit](https://github.com/BYVoid/OpenCC/commit/6b382c6489efe4874350ec33531b46b32e08c2d5))。 +* **打包 / 構建系統**: + * 重建 Debian 打包流程:新增頂層 `debian/` 目錄使 `dpkg-buildpackage` 可端到端重現 Debian 構建,`packaging/debian/` 補丁鏡像與 ver.1.4.0 源碼對齊,並改進 deb 構建腳本與 workflow([#1398](https://github.com/BYVoid/OpenCC/pull/1398), [#1385](https://github.com/BYVoid/OpenCC/pull/1385), [#1406](https://github.com/BYVoid/OpenCC/pull/1406))。 + * Bazel 升級至 9.1.1([#1384](https://github.com/BYVoid/OpenCC/pull/1384));`rules_node_addon` 更新至 BCR 1.0.3([#1370](https://github.com/BYVoid/OpenCC/pull/1370))。 + * MSVC `/W4` 改用 `add_compile_options` 設定,避免 `rc.exe` 資源編譯失敗([#1393](https://github.com/BYVoid/OpenCC/pull/1393));CMake 恢復支援舊式 Python executable 選項([#1389](https://github.com/BYVoid/OpenCC/pull/1389))。 + * 新增 `opencc-v-resources.zip` 資源包發佈 workflow;`release-pypi` workflow 新增 push tag 觸發,與其他發佈 workflow 一致。 + * 穩定 Doxygen 文檔頁面 anchor ID,不再隨構建路徑變化([#1400](https://github.com/BYVoid/OpenCC/pull/1400))。 +* **測試**: + * 新增 librime OpenCC 相容性測試,覆蓋 `GetConversionChain`、精確詞條展開與前綴匹配 fallback([#1395](https://github.com/BYVoid/OpenCC/pull/1395))。 ## Version 1.4.0 diff --git a/README.md b/README.md index 18061ae8f..dd49005bb 100644 --- a/README.md +++ b/README.md @@ -55,15 +55,16 @@ Discussion (Telegram): https://t.me/open_chinese_convert ### Prebuilt binaries 預編譯二進位檔 -OpenCC 1.4.0 主要更新是將 C++ ABI / SOVERSION 提升至 1.4,避免舊版 -`libopencc.so.1.3` 使用者靜默載入 ABI 不相容的新版本;下游 C++ 程式需重新鏈結。 +OpenCC 1.4.1 修復 `opencc` npm 套件在無預編譯二進制平台上源碼編譯安裝失敗的 +問題,並包含一批詞庫修正;C++ ABI 與 1.4.0 相同(SOVERSION 1.4),自 1.4.0 +升級的下游 C++ 程式無需重新鏈結。 -* Windows (x86_64): [OpenCC-1.4.0](https://github.com/BYVoid/OpenCC/releases/download/ver.1.4.0/OpenCC-1.4.0-windows-x64-portable.zip) ([SHA-256](https://github.com/BYVoid/OpenCC/releases/download/ver.1.4.0/OpenCC-1.4.0-windows-x64-portable.zip.sha256)) +* Windows (x86_64): [OpenCC-1.4.1](https://github.com/BYVoid/OpenCC/releases/download/ver.1.4.1/OpenCC-1.4.1-windows-x64-portable.zip) ([SHA-256](https://github.com/BYVoid/OpenCC/releases/download/ver.1.4.1/OpenCC-1.4.1-windows-x64-portable.zip.sha256)) * This Windows release is available from WinGet. For details, see [doc/windows-winget-release.md](doc/windows-winget-release.md). * Requires Microsoft Visual C++ Redistributable for Visual Studio 2015-2026. Download the latest version from [Microsoft](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-supported-redistributable-version). * Debian/Ubuntu (amd64): - * [opencc_1.4.0_amd64.deb](https://github.com/BYVoid/OpenCC/releases/download/ver.1.4.0/opencc_1.4.0_amd64.deb) - * [opencc-jieba_1.4.0_amd64.deb](https://github.com/BYVoid/OpenCC/releases/download/ver.1.4.0/opencc-jieba_1.4.0_amd64.deb) + * [opencc_1.4.1_amd64.deb](https://github.com/BYVoid/OpenCC/releases/download/ver.1.4.1/opencc_1.4.1_amd64.deb) + * [opencc-jieba_1.4.1_amd64.deb](https://github.com/BYVoid/OpenCC/releases/download/ver.1.4.1/opencc-jieba_1.4.1_amd64.deb) ## Usage 使用 diff --git a/node/BUILD.bazel b/node/BUILD.bazel index e2d292d12..1c0806461 100644 --- a/node/BUILD.bazel +++ b/node/BUILD.bazel @@ -47,7 +47,7 @@ node_addon( "//conditions:default": ["-std=c++20"], }), defines = [ - 'OPENCC_VERSION=\\"1.4.0\\"', + 'OPENCC_VERSION=\\"1.4.1\\"', "NAPI_DISABLE_CPP_EXCEPTIONS", "Opencc_BUILT_AS_STATIC", ], diff --git a/node/PUBLISHING.md b/node/PUBLISHING.md index 82ccfb213..a5608b072 100644 --- a/node/PUBLISHING.md +++ b/node/PUBLISHING.md @@ -64,7 +64,8 @@ prebuilds/-/opencc.node The release workflow runs the Bazel build script separately on the runner for each scoped binary target. The main `opencc` package still keeps `binding.gyp` and source files so installs on platforms without a scoped binary package can -fall back to `node-gyp-build`. +fall back to `node-gyp-build`. This fallback is planned for removal in a +future release, after which all Node builds will use Bazel exclusively. ## Prepare scoped binary packages diff --git a/node/global.gypi b/node/global.gypi index e876f9341..98b91b6d2 100644 --- a/node/global.gypi +++ b/node/global.gypi @@ -1,6 +1,6 @@ { "variables": { - "opencc_version": "1.4.0" + "opencc_version": "1.4.1" }, "target_defaults": { "defines": [ diff --git a/scripts/build-cli-windows-zig.sh b/scripts/build-cli-windows-zig.sh index fd4394367..d976c74a8 100755 --- a/scripts/build-cli-windows-zig.sh +++ b/scripts/build-cli-windows-zig.sh @@ -48,7 +48,7 @@ if [[ -z "$version" ]]; then MODULE.bazel | head -n 1 )" fi -version="${version:-1.4.0}" +version="${version:-1.4.1}" export ZIG_LOCAL_CACHE_DIR="${ZIG_LOCAL_CACHE_DIR:-$ROOT_DIR/.zig-local-cache}" export ZIG_GLOBAL_CACHE_DIR="${ZIG_GLOBAL_CACHE_DIR:-$ROOT_DIR/.zig-global-cache}" diff --git a/scripts/build-node-windows-zig.sh b/scripts/build-node-windows-zig.sh index a004d51b7..fd69113f7 100755 --- a/scripts/build-node-windows-zig.sh +++ b/scripts/build-node-windows-zig.sh @@ -69,7 +69,7 @@ set +e -w \ -Wno-nullability-completeness \ -DNDEBUG \ - '-DOPENCC_VERSION="1.4.0"' \ + '-DOPENCC_VERSION="1.4.1"' \ -DNAPI_DISABLE_CPP_EXCEPTIONS \ -DOpencc_BUILT_AS_STATIC \ -I. \ diff --git a/setup.py b/setup.py index 309ba25a2..55bdab25b 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ _cmake_file = os.path.join(_this_dir, 'CMakeLists.txt') _author_file = os.path.join(_this_dir, 'AUTHORS') _readme_file = os.path.join(_this_dir, 'README.md') -_fallback_version = '1.4.0' +_fallback_version = '1.4.1' def _get_version_from_git(): From d730cd7d6b37629cf10fd26f26e57e4d326d4389 Mon Sep 17 00:00:00 2001 From: Frank Lin Date: Sat, 11 Jul 2026 15:18:48 -0700 Subject: [PATCH 4/7] Bump remaining 1.4.0 release references to 1.4.1 Update the Bazel module version, add a 1.4.1-1 Debian changelog entry (release-deb.yml stamps deb artifacts with dpkg-parsechangelog, which would otherwise still report 1.4.0-1), rebase debian patch 0004 whose context shifted after the post-1.4.0 bundled-googletest existence check, and refresh the packaging docs' upstream-version statements. All four patches re-verified with patch -p1 --fuzz=0 against the current tree. --- MODULE.bazel | 2 +- packaging/debian/README.md | 6 +++--- packaging/debian/SPLIT_PROPOSAL.md | 2 +- packaging/debian/debian/README.source | 4 ++-- packaging/debian/debian/changelog | 15 +++++++++++++++ .../patches/0004-Use-system-googletest.patch | 14 +++++++------- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index e6e82c5a4..e69fd0014 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -2,7 +2,7 @@ module( name = "opencc", - version = "1.4.0", + version = "1.4.1", ) bazel_dep(name = "aspect_bazel_lib", version = "2.22.5") diff --git a/packaging/debian/README.md b/packaging/debian/README.md index 7f0ee43b0..abe284a42 100644 --- a/packaging/debian/README.md +++ b/packaging/debian/README.md @@ -9,7 +9,7 @@ It is not the authoritative Debian packaging source. This patch set is based on: -- Upstream: BYVoid/OpenCC `ver.1.4.0` +- Upstream: BYVoid/OpenCC `ver.1.4.1` - Debian source package: `opencc 1.3.1+ds1-3` - Debian packaging repository: https://salsa.debian.org/debian/opencc @@ -29,9 +29,9 @@ This is the complete active set. Patch numbering reflects historical Debian quilt ordering and is not contiguous. -## 3. Patch status against upstream 1.4.0 +## 3. Patch status against upstream 1.4.1 -All patches have been re-based against upstream `1.4.0` and verified to apply cleanly: +All patches have been re-based against upstream `1.4.1` and verified to apply cleanly: - `patch -p1 --fuzz=0` compatibility - tested in clean upstream checkout diff --git a/packaging/debian/SPLIT_PROPOSAL.md b/packaging/debian/SPLIT_PROPOSAL.md index 1a47aa7d9..5ae62c3d1 100644 --- a/packaging/debian/SPLIT_PROPOSAL.md +++ b/packaging/debian/SPLIT_PROPOSAL.md @@ -2,7 +2,7 @@ This is a proposal from upstream, not a Debian upload. It was produced by overlaying the top-level `debian/` directory onto a clean checkout of -upstream `BYVoid/OpenCC` at `master` (1.4.0) and actually running +upstream `BYVoid/OpenCC` at `master` (1.4.1) and actually running `dpkg-buildpackage -us -uc -b` there, on Ubuntu 24.04 with debhelper 13.14. All six binary packages built, `dh_missing --fail-missing` found nothing unclaimed, `ctest` passed 19/19, and `lintian --pedantic` diff --git a/packaging/debian/debian/README.source b/packaging/debian/debian/README.source index 6df958a29..999a86ce6 100644 --- a/packaging/debian/debian/README.source +++ b/packaging/debian/debian/README.source @@ -5,12 +5,12 @@ checkout of upstream BYVoid/OpenCC (e.g. `cp -r packaging/debian/debian /debian`) and run `dpkg-buildpackage` from there. This debian/ directory is authored against upstream BYVoid/OpenCC's file -layout at 1.4.0, and was validated by running `dpkg-buildpackage -us -uc +layout at 1.4.1, and was validated by running `dpkg-buildpackage -us -uc -b` against a clean checkout of upstream `master` (all six binary packages build, `dh_missing --fail-missing` finds nothing unclaimed, `ctest` passes 19/19, and `lintian --pedantic` reports no errors). It authored strictly against the file layout present in the upstream source -tree at 1.4.0 — building it against any checkout that contains files +tree at 1.4.1 — building it against any checkout that contains files beyond what upstream ships will cause dh_missing to fail on those extra files. diff --git a/packaging/debian/debian/changelog b/packaging/debian/debian/changelog index 821be67f1..76a437da9 100644 --- a/packaging/debian/debian/changelog +++ b/packaging/debian/debian/changelog @@ -1,3 +1,18 @@ +opencc (1.4.1-1) UNRELEASED; urgency=medium + + * Update packaging for the upstream 1.4.1 release: + - Rebase 0004 (use system-installed googletest) against 1.4.1; the + ENABLE_GTEST block gained a bundled-source existence check that + shifted the hunk context. 0003, 0005 and 0009 apply unchanged. All + four patches verified with `patch -p1 --fuzz=0` against upstream + 1.4.1 sources. + - Drop usr/bin/cppjieba_dict from opencc-jieba.install: upstream now + generates the merged Jieba dictionary with the regular opencc_dict + tool (shipped in the opencc package) and no longer builds or + installs a separate dictionary helper. + + -- Frank Lin Sat, 11 Jul 2026 00:00:00 +0000 + opencc (1.4.0-1) UNRELEASED; urgency=medium * Recreate the Debian packaging flow on top of the existing diff --git a/packaging/debian/debian/patches/0004-Use-system-googletest.patch b/packaging/debian/debian/patches/0004-Use-system-googletest.patch index d65f11c97..a2e4ae453 100644 --- a/packaging/debian/debian/patches/0004-Use-system-googletest.patch +++ b/packaging/debian/debian/patches/0004-Use-system-googletest.patch @@ -2,18 +2,18 @@ From: Shengjing Zhu Date: Sun, 28 Jul 2024 19:44:27 -0400 Subject: Use system-installed googletest via CMake package discovery -Rebased for opencc 1.4.0: the ENABLE_GTEST block gained a bundled-source -existence check ahead of the USE_SYSTEM_GTEST branch since this patch -was written, so the else() is now attached further down; only that -if/else/endif is touched here. +Rebased for opencc 1.4.1: the ENABLE_GTEST block gained a bundled-source +existence check ahead of the USE_SYSTEM_GTEST branch since 1.4.0 (source +package profiles may strip deps/googletest), shifting this hunk's +context; only the if/else/endif around add_subdirectory is touched here. Forwarded: not-needed -Last-Update: 2026-07-04 +Last-Update: 2026-07-11 --- --- OpenCC.orig/CMakeLists.txt +++ OpenCC/CMakeLists.txt -@@ -309,6 +309,8 @@ endif() - if (ENABLE_GTEST) +@@ -395,6 +395,8 @@ + endif() if(NOT USE_SYSTEM_GTEST) add_subdirectory(deps/googletest-1.15.0) + else() From 06fdc0117f523942bdd479699c28ebb96dbf8746 Mon Sep 17 00:00:00 2001 From: Frank Lin Date: Sat, 11 Jul 2026 20:04:13 -0700 Subject: [PATCH 5/7] Fix standalone Jieba plugin configure with a prefix-installed opencc_dict opencc_dict installed to a non-default prefix carries no rpath, so running it during the standalone plugin configure failed to load libopencc and the cppjieba_utf8 capability check misreported the tool as too old (as seen in the cmake.yml standalone job). Wrap the opencc_dict invocation with cmake -E env to prepend the installation's lib directory to DYLD_LIBRARY_PATH / LD_LIBRARY_PATH on macOS / Linux, use the same wrapped command for both the configure-time check and the dictionary generation rule, and report a failed-to-run opencc_dict distinctly from a missing cppjieba_utf8 format. --- plugins/jieba/CMakeLists.txt | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/plugins/jieba/CMakeLists.txt b/plugins/jieba/CMakeLists.txt index fd70b83b0..aa5371bed 100644 --- a/plugins/jieba/CMakeLists.txt +++ b/plugins/jieba/CMakeLists.txt @@ -159,18 +159,41 @@ if (OPENCC_CAN_RUN_CPPJIEBA_DICT) "opencc_dict not found. Building the merged Jieba dictionary requires " "the opencc_dict tool from OpenCC 1.4.1 or later.") endif() + # An opencc_dict installed to a non-default prefix carries no rpath, so + # help the dynamic linker find libopencc from the same installation. + get_filename_component(_opencc_dict_bindir + "${OPENCC_DICT_EXECUTABLE}" DIRECTORY) + get_filename_component(_opencc_dict_prefix + "${_opencc_dict_bindir}" DIRECTORY) + if (WIN32) + # The installed layout keeps opencc.dll next to opencc_dict.exe. + set(OPENCC_DICT_COMMAND "${OPENCC_DICT_EXECUTABLE}") + elseif (APPLE) + set(OPENCC_DICT_COMMAND ${CMAKE_COMMAND} -E env + "DYLD_LIBRARY_PATH=${_opencc_dict_prefix}/lib:$ENV{DYLD_LIBRARY_PATH}" + "${OPENCC_DICT_EXECUTABLE}") + else() + set(OPENCC_DICT_COMMAND ${CMAKE_COMMAND} -E env + "LD_LIBRARY_PATH=${_opencc_dict_prefix}/lib:$ENV{LD_LIBRARY_PATH}" + "${OPENCC_DICT_EXECUTABLE}") + endif() execute_process( - COMMAND "${OPENCC_DICT_EXECUTABLE}" --help + COMMAND ${OPENCC_DICT_COMMAND} --help + RESULT_VARIABLE _opencc_dict_help_result OUTPUT_VARIABLE _opencc_dict_help ERROR_VARIABLE _opencc_dict_help_err ) + if (NOT _opencc_dict_help_result EQUAL 0) + message(FATAL_ERROR + "Failed to run ${OPENCC_DICT_EXECUTABLE} (exit status " + "${_opencc_dict_help_result}): ${_opencc_dict_help_err}") + endif() if (NOT "${_opencc_dict_help}${_opencc_dict_help_err}" MATCHES "cppjieba_utf8") message(FATAL_ERROR "${OPENCC_DICT_EXECUTABLE} does not support the cppjieba_utf8 input " "format. OpenCC 1.4.1 or later is required.") endif() - set(OPENCC_DICT_COMMAND "${OPENCC_DICT_EXECUTABLE}") set(OPENCC_DICT_TARGET_DEPENDS) else() set(OPENCC_DICT_COMMAND opencc_dict) From 9cdd4fa62f4657b9a72907783d1e7c149e337441 Mon Sep 17 00:00:00 2001 From: Frank Lin Date: Sat, 11 Jul 2026 20:20:35 -0700 Subject: [PATCH 6/7] Lower opencc-jieba npm macOS deployment target to 11.0 The plugin binary built by plugins/jieba/node/build.js inherited the CI runner's OS version as its minimum macOS version (15.0 on macos-15 runners), while the Bazel-built opencc npm binaries target 11.0. Pass CMAKE_OSX_DEPLOYMENT_TARGET=11.0 on darwin so both npm packages support the same macOS range; verified the rebuilt libopencc-jieba.dylib now reports minos 11.0. --- plugins/jieba/node/build.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/jieba/node/build.js b/plugins/jieba/node/build.js index 3659bb04c..575ce42d1 100644 --- a/plugins/jieba/node/build.js +++ b/plugins/jieba/node/build.js @@ -97,6 +97,9 @@ run('cmake', [ '-DBUILD_OPENCC_JIEBA_PLUGIN=ON', '-DENABLE_GTEST=OFF', '-DENABLE_BENCHMARK=OFF', + // Match the minimum macOS version of the Bazel-built opencc npm binaries; + // without this the plugin inherits the build host's OS version as minos. + ...(platform === 'darwin' ? ['-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0'] : []), ]); run('cmake', [ From 74d077d9cb36f6a8e69e704fe08791489bc1a376 Mon Sep 17 00:00:00 2001 From: Frank Lin Date: Sat, 11 Jul 2026 20:20:51 -0700 Subject: [PATCH 7/7] Note opencc-jieba macOS deployment target fix in 1.4.1 release notes --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index fa6a2159e..7e151339d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -20,6 +20,7 @@ * **Node.js**: * 修復 npm 源碼包缺少 `src/ConfigBasedConverter.hpp`、`src/PipelineConverter.cpp/.hpp`、`src/SingleStageConverter.cpp/.hpp`、`src/opencc_config_schema.inc` 六個編譯所需檔案,導致 `npm install` 源碼編譯失敗([#1409](https://github.com/BYVoid/OpenCC/issues/1409), [#1411](https://github.com/BYVoid/OpenCC/pull/1411))。 * 新增 `@opencc/opencc-darwin-x64` 與 `@opencc/opencc-jieba-darwin-x64` 預編譯套件,Intel Mac 不再需要源碼編譯([#1411](https://github.com/BYVoid/OpenCC/pull/1411))。 + * `opencc-jieba` 預編譯二進制的 macOS 最低版本從構建機的 15.0 降至 11.0,與 `opencc` 主套件的預編譯二進制一致。 * `prepack` 驗證腳本新增 gyp 源碼與 `#include` 閉包檢查,確保源碼編譯所需的所有檔案都在 npm 包的 `files` 白名單內,防止同類問題再次發生。 * CI 新增「從 `npm pack` 產出的 tarball 進行源碼編譯並安裝」的測試(ubuntu / macOS ARM / macOS Intel),覆蓋無預編譯二進制平台的實際安裝路徑。 * JavaScript API 支援以 inline config 物件建立轉換器,保留原有字串配置行為;並覆蓋 bundled assets、自定義配置目錄與 tofu-risk 過濾的測試([#1412](https://github.com/BYVoid/OpenCC/pull/1412))。