UNPKG

nnocr

Version:

Native Node.js bindings for the Tesseract OCR project.

197 lines (164 loc) 5.75 kB
const fs = require('fs'); const path = require('path'); const shell = require('shelljs'); const process = require("process"); const requiredCMakeVersion = '3.15'; const cmakeBuildType = 'Release'; shell.config.fatal = true; // thrown an exception on any error let commonEnvVariables = { CMAKE_BUILD_TYPE: cmakeBuildType, CMAKE_INSTALL_PREFIX: '${PWD}/bin', BUILD_SHARED_LIBS: 'OFF', CMAKE_POSITION_INDEPENDENT_CODE: 'ON', CMAKE_MSVC_RUNTIME_LIBRARY: 'MultiThreaded', CMAKE_POLICY_DEFAULT_CMP0091: 'NEW', CMAKE_OSX_DEPLOYMENT_TARGET: '10.9' } const buildForArch = process.env["BUILD_FOR_ARCH"] || process.arch; shell.echo('buildForArch', buildForArch); if (buildForArch === 'arm64') { shell.echo('arm64 build'); commonEnvVariables = { ...commonEnvVariables, CMAKE_OSX_ARCHITECTURES: '\"arm64\"' } } else if (buildForArch === 'x64') { shell.echo('x64 build'); commonEnvVariables = { ...commonEnvVariables, CMAKE_OSX_ARCHITECTURES: '\"x86_64\"' } } // ------ startup ------ shell.echo('build-tesseract script start.'); if (!shell.which('git')) { shell.echo('This script requires Git.'); shell.exit(1); } checkCMakeVersion(); const homeDir = path.resolve(__dirname,'..'); shell.cd(homeDir); shell.echo(`Working directory: ${homeDir}`); // ------ libraries ------ buildLibjpeg ('libjpeg'); buildLeptonica ('leptonica'); buildTesseract ('tesseract'); shell.echo('build-tesseract script end.'); function checkCMakeVersion() { let versionOK = false; shell.echo(`This script requires CMake version ${requiredCMakeVersion} or later.`); if (!shell.which('cmake')) { shell.echo('CMake not found on this system.'); } else { const reply = shell.exec('cmake --version', {silent: true}); foundVersion = (/\d+.\d+.\d+/mg).exec(reply)[0]; versionOK = checkVersion(foundVersion, requiredCMakeVersion) >= 0; if (versionOK) { shell.echo(`CMake ${foundVersion} found on this system.`); } else { shell.echo(`CMake ${foundVersion} found on this system is too old.`); } } if (!versionOK) shell.exit(1); } // https://codereview.stackexchange.com/questions/236647/comparing-version-numbers-with-javascript function checkVersion (a, b) { const x = a.split('.').map(e => parseInt(e, 10)); const y = b.split('.').map(e => parseInt(e, 10)); for (const i in x) { y[i] = y[i] || 0; if (x[i] === y[i]) { continue; } else if (x[i] > y[i]) { return 1; } else { return -1; } } return y.length > x.length ? -1 : 0; } function buildLibjpeg (dirName) { shell.echo('Building libjpeg.'); if (shell.test('-e', dirName)) { shell.echo(`The ${dirName} directory already exists.`); } else { shell.exec(`git clone https://github.com/tamaskenez/libjpeg-cmake.git ${dirName}`); } runCMakeBuild (dirName, cmakeBuildType); } function buildLeptonica (dirName) { shell.echo('Building Leptonica.'); runCMakeBuild (dirName, cmakeBuildType, { SW_BUILD: 'OFF', CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: 'FALSE', CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: process.platform === 'darwin' ? 'FALSE' : 'TRUE', CMAKE_PREFIX_PATH: '${PWD}/../../libjpeg/build', CMAKE_INCLUDE_PATH: '${PWD}/../../libjpeg/build/bin/include', CMAKE_LIBRARY_PATH: '${PWD}/../../libjpeg/build/bin/lib' }, (dirName, cmakeConfig, envVars) => { // patch config_auto.h between config and build if (process.platform === 'darwin') { const filePath = path.resolve(__dirname,'..',dirName,'build','src','config_auto.h'); shell.echo(`Patching ${filePath} for Mac.`); let autoConfig = fs.readFileSync(filePath, 'utf8'); const searchText = /^#define\s+HAVE_FMEMOPEN\s+1/gm; const replacementText = '#define HAVE_FMEMOPEN 0'; const foundText = autoConfig.match(searchText); if (foundText) { const updatedConfig = autoConfig.replace(searchText, replacementText); fs.writeFileSync(filePath, updatedConfig, 'utf8'); shell.echo(`The '${foundText}' directive was replaced with '${replacementText}'.`); } else { shell.echo(`The '#define HAVE_FMEMOPEN 1' directive was not found.`); shell.echo('This may lead to a build that does not run on all macOS machines.'); } } } ); } function buildTesseract (dirName) { shell.echo('Building Tesseract.'); runCMakeBuild (dirName, cmakeBuildType, { STATIC: 'ON', CPPAN_BUILD: 'OFF', BUILD_TRAINING_TOOLS: 'OFF', AUTO_OPTIMIZE: 'OFF', Leptonica_DIR: '../leptonica/build' } ); } function runCMakeBuild (dirName, cmakeBuildType, envVars, patchConfig) { createAndEnterBuildDir(dirName); let cmakeCmd = 'cmake'; cmakeCmd += formatEnvVars (envVars); cmakeCmd += formatEnvVars (commonEnvVariables); cmakeCmd += ' ..'; shell.echo(`Configuring a ${cmakeBuildType} build.`) shell.echo(cmakeCmd); shell.exec(cmakeCmd); if (patchConfig) patchConfig(dirName, cmakeBuildType, envVars); shell.echo(`Creating a ${cmakeBuildType} build.`) shell.exec(`cmake --build . --config ${cmakeBuildType}`); shell.echo(`Installing a ${cmakeBuildType} build.`) shell.exec('cmake --install .'); leaveBuildDir(); } function createAndEnterBuildDir (dirName) { shell.pushd('-q', dirName); if (!shell.test('-e', 'build')) shell.mkdir('build'); shell.pushd('-q', 'build'); } function leaveBuildDir() { shell.popd('-q'); shell.popd('-q'); } function formatEnvVars (envVars) { const continuation = process.platform === 'win32' ? '' : ' \\\n'; let args = ''; for (key in envVars) { args += ` -D${key}=${envVars[key]}${continuation}`; } return args; }