Skip to content

Commit

Permalink
Improve #include handling for JS library files
Browse files Browse the repository at this point in the history
Files references via #include can now either relative to the including
file or come from the system library.  Previously only relative paths
were allowed.

Also we now give a nicer error message when the file is not found.
  • Loading branch information
sbc100 committed Jan 17, 2025
1 parent 186cae3 commit 55f86fc
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 5 deletions.
29 changes: 25 additions & 4 deletions src/parseTools.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import * as path from 'node:path';
import {existsSync} from 'node:fs';

import {
addToCompileTimeContext,
Expand All @@ -19,6 +20,7 @@ import {
runInMacroContext,
setCurrentFile,
warn,
srcDir,
} from './utility.mjs';

const FOUR_GB = 4 * 1024 * 1024 * 1024;
Expand All @@ -40,6 +42,24 @@ export function processMacros(text, filename) {
});
}

function findIncludeFile(filename, currentDir) {
if (path.isAbsolute(filename)) {
return existsSync(filename) ? filename : null;
}

// Search for include files either relative to the including file,
// or in the src root directory.
const includePath = [currentDir, srcDir];
for (const p of includePath) {
const f = path.join(p, filename);
if (existsSync(f)) {
return f;
}
}

return null;
}

// Simple #if/else/endif preprocessing for a file. Checks if the
// ident checked is true in our global.
// Also handles #include x.js (similar to C #include <file>)
Expand Down Expand Up @@ -125,11 +145,12 @@ export function preprocess(filename) {
if (includeFile.startsWith('"')) {
includeFile = includeFile.substr(1, includeFile.length - 2);
}
// Include files are always relative to the current file being processed
if (!path.isAbsolute(includeFile)) {
includeFile = path.join(path.dirname(filename), includeFile);
const absPath = findIncludeFile(includeFile, path.dirname(filename));
if (!absPath) {
error(`${filename}:${i + 1}: file not found: ${includeFile}`);
continue;
}
const result = preprocess(includeFile);
const result = preprocess(absPath);
if (result) {
ret += `// include: ${includeFile}\n`;
ret += result;
Expand Down
4 changes: 3 additions & 1 deletion src/utility.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,13 @@ export function read(filename) {
// Use import.meta.dirname here once we drop support for node v18.
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

export const srcDir = __dirname;

// Returns an absolute path for a file, resolving it relative to this script
// (i.e. relative to the src/ directory).
export function localFile(filename) {
assert(!path.isAbsolute(filename));
return path.join(__dirname, filename);
return path.join(srcDir, filename);
}

// Anything needed by the script that we load below must be added to the
Expand Down
16 changes: 16 additions & 0 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -4922,6 +4922,22 @@ def test_jslib_errors(self):
self.assertContained('error_in_js_libraries.js:5: #error This is an error string!', err)
self.assertContained('error_in_js_libraries.js:7: #error This is a second error string!', err)

def test_jslib_include(self):
create_file('inc.js', '''
let MY_VAR = 10;
''')
create_file('foo.js', '''
// Include a file from system directory
#include "arrayUtils.js"
// Include a local file.
#include "inc.js"
''')
self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'foo.js'])

delete_file('inc.js')
err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'foo.js'])
self.assertContained('foo.js:5: file not found: inc.js', err)

def test_postjs_errors(self):
create_file('post.js', '#preprocess\n#error This is an error')
err = self.expect_fail([EMCC, test_file('hello_world.c'), '--post-js', 'post.js'])
Expand Down

0 comments on commit 55f86fc

Please sign in to comment.