From 1155084e75203a53d0b9e143808c25c8dda314d7 Mon Sep 17 00:00:00 2001 From: Tal Hadad Date: Wed, 14 May 2025 13:02:35 +0300 Subject: [PATCH 1/7] fix: preserve the absolutness/relativeness of the included file. Note: if relative, it will be normalized always relatively to the current directory Note: still avoid cases of double header detection (relative vs. absolute) --- simplecpp.cpp | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/simplecpp.cpp b/simplecpp.cpp index 25c4124a..c2b10788 100755 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -3145,11 +3145,11 @@ static std::string openHeader(std::ifstream &f, const std::string &path) return ""; } -static std::string getRelativeFileName(const std::string &sourcefile, const std::string &header) +static std::string getRelativeFileName(const std::string &baseFile, const std::string &header) { std::string path; - if (sourcefile.find_first_of("\\/") != std::string::npos) - path = sourcefile.substr(0, sourcefile.find_last_of("\\/") + 1U) + header; + if (baseFile.find_first_of("\\/") != std::string::npos) + path = baseFile.substr(0, baseFile.find_last_of("\\/") + 1U) + header; else path = header; return simplecpp::simplifyPath(path); @@ -3160,12 +3160,22 @@ static std::string openHeaderRelative(std::ifstream &f, const std::string &sourc return openHeader(f, getRelativeFileName(sourcefile, header)); } +// returns the simplified header path: +// * If the header path is absolute, returns it in absolute path +// * Otherwise, returns it in relative path with respect to the current directory static std::string getIncludePathFileName(const std::string &includePath, const std::string &header) { - std::string path = toAbsolutePath(includePath); - if (!path.empty() && path[path.size()-1U]!='/' && path[path.size()-1U]!='\\') - path += '/'; - return path + header; + std::string simplifiedHeader = simplecpp::simplifyPath(header); + + if (isAbsolutePath(simplifiedHeader)) { + return simplifiedHeader; + } + + std::string basePath = toAbsolutePath(includePath); + if (!basePath.empty() && basePath[basePath.size()-1U]!='/' && basePath[basePath.size()-1U]!='\\') + basePath += '/'; + std::string absolutesimplifiedHeaderPath = basePath + simplifiedHeader; + return extractRelativePathFromAbsolute(absolutesimplifiedHeaderPath).first; } static std::string openHeaderIncludePath(std::ifstream &f, const simplecpp::DUI &dui, const std::string &header) @@ -3183,17 +3193,16 @@ static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const if (isAbsolutePath(header)) return openHeader(f, header); - if (systemheader) { - // always return absolute path for systemheaders - return toAbsolutePath(openHeaderIncludePath(f, dui, header)); + // prefer first to search the header relatively to source file if found, when not a system header + if (!systemheader) { + std::string relativeHeader = openHeaderRelative(f, sourcefile, header); + if (!relativeHeader.empty()) { + return relativeHeader; + } } - std::string ret; - - ret = openHeaderRelative(f, sourcefile, header); - if (ret.empty()) - return toAbsolutePath(openHeaderIncludePath(f, dui, header));// in a similar way to system headers - return ret; + // search the header on the include paths (provided by the flags "-I...") + return openHeaderIncludePath(f, dui, header); } static std::string findPathInMapBothRelativeAndAbsolute(const std::map &filedata, const std::string& path) { @@ -3235,18 +3244,17 @@ static std::string getFileIdPath(const std::map::const_iterator it = dui.includePaths.begin(); it != dui.includePaths.end(); ++it) { - const std::string match = findPathInMapBothRelativeAndAbsolute(filedata, simplecpp::simplifyPath(getIncludePathFileName(*it, header))); + const std::string match = findPathInMapBothRelativeAndAbsolute(filedata, getIncludePathFileName(*it, header)); if (!match.empty()) { return match; } } - if (systemheader && filedata.find(header) != filedata.end()) - return header;// system header that its file wasn't found in the included paths but alreasy in the filedata - return this as is - return ""; } From 29be0786390c3b15174638769694ff681736cbe3 Mon Sep 17 00:00:00 2001 From: Tal Hadad Date: Wed, 14 May 2025 14:42:42 +0300 Subject: [PATCH 2/7] fix the absolute path case --- simplecpp.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/simplecpp.cpp b/simplecpp.cpp index c2b10788..dfb6a176 100755 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -3221,8 +3221,9 @@ static std::string findPathInMapBothRelativeAndAbsolute(const std::map Date: Wed, 14 May 2025 14:46:47 +0300 Subject: [PATCH 3/7] tidy fix --- simplecpp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simplecpp.cpp b/simplecpp.cpp index dfb6a176..d1fa91bf 100755 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -3174,7 +3174,7 @@ static std::string getIncludePathFileName(const std::string &includePath, const std::string basePath = toAbsolutePath(includePath); if (!basePath.empty() && basePath[basePath.size()-1U]!='/' && basePath[basePath.size()-1U]!='\\') basePath += '/'; - std::string absolutesimplifiedHeaderPath = basePath + simplifiedHeader; + const std::string absolutesimplifiedHeaderPath = basePath + simplifiedHeader; return extractRelativePathFromAbsolute(absolutesimplifiedHeaderPath).first; } From af84e454d244b01ca93fa75c94554298116dd5f9 Mon Sep 17 00:00:00 2001 From: Tal Hadad Date: Thu, 15 May 2025 19:13:56 +0300 Subject: [PATCH 4/7] add integration tests --- integration_test.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/integration_test.py b/integration_test.py index 0b2b0b38..f000f854 100644 --- a/integration_test.py +++ b/integration_test.py @@ -14,6 +14,7 @@ def __test_relative_header_create_header(dir, with_pragma_once=True): #else #error header_was_already_included #endif + const int dummy = 1; """) return header_file, "error: #error header_was_already_included" @@ -48,33 +49,43 @@ def test_relative_header_1(tmpdir, with_pragma_once, is_sys): assert double_include_error in stderr @pytest.mark.parametrize("inv", (False, True)) -def test_relative_header_2(tmpdir, inv): +@pytest.mark.parametrize("source_relative", (False, True)) +def test_relative_header_2(tmpdir, inv, source_relative): header_file, _ = __test_relative_header_create_header(tmpdir) test_file = __test_relative_header_create_source(tmpdir, "test.h", header_file, inv=inv) - args = [test_file] + args = ["test.c" if source_relative else test_file] - _, _, stderr = simplecpp(args, cwd=tmpdir) + _, stdout, stderr = simplecpp(args, cwd=tmpdir) assert stderr == '' + if source_relative and not inv: + assert '#line 8 "test.h"' in stdout + else: + assert f'#line 8 "{tmpdir}/test.h"' in stdout @pytest.mark.parametrize("is_sys", (False, True)) @pytest.mark.parametrize("inv", (False, True)) -def test_relative_header_3(tmpdir, is_sys, inv): +@pytest.mark.parametrize("source_relative", (False, True)) +def test_relative_header_3(tmpdir, is_sys, inv, source_relative): test_subdir = os.path.join(tmpdir, "test_subdir") os.mkdir(test_subdir) header_file, _ = __test_relative_header_create_header(test_subdir) test_file = __test_relative_header_create_source(tmpdir, "test_subdir/test.h", header_file, is_include1_sys=is_sys, inv=inv) - args = [test_file] + args = ["test.c" if source_relative else test_file] - _, _, stderr = simplecpp(args, cwd=tmpdir) + _, stdout, stderr = simplecpp(args, cwd=tmpdir) if is_sys: assert "missing header: Header not found" in stderr else: assert stderr == '' + if source_relative and not inv: + assert '#line 8 "test_subdir/test.h"' in stdout + else: + assert f'#line 8 "{test_subdir}/test.h"' in stdout @pytest.mark.parametrize("use_short_path", (False, True)) @pytest.mark.parametrize("is_sys", (False, True)) From 11fd714a426270754c0b650246d75226808db947 Mon Sep 17 00:00:00 2001 From: Tal Hadad Date: Thu, 15 May 2025 19:23:44 +0300 Subject: [PATCH 5/7] fix integration test for windows --- integration_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integration_test.py b/integration_test.py index f000f854..5ec80ee5 100644 --- a/integration_test.py +++ b/integration_test.py @@ -1,6 +1,7 @@ ## test with python -m pytest integration_test.py import os +import pathlib import pytest from testutils import simplecpp, format_include_path_arg, format_include @@ -62,7 +63,7 @@ def test_relative_header_2(tmpdir, inv, source_relative): if source_relative and not inv: assert '#line 8 "test.h"' in stdout else: - assert f'#line 8 "{tmpdir}/test.h"' in stdout + assert f'#line 8 "{pathlib.PosixPath(tmpdir)}/test.h"' in stdout @pytest.mark.parametrize("is_sys", (False, True)) @pytest.mark.parametrize("inv", (False, True)) @@ -85,7 +86,7 @@ def test_relative_header_3(tmpdir, is_sys, inv, source_relative): if source_relative and not inv: assert '#line 8 "test_subdir/test.h"' in stdout else: - assert f'#line 8 "{test_subdir}/test.h"' in stdout + assert f'#line 8 "{pathlib.PosixPath(test_subdir)}/test.h"' in stdout @pytest.mark.parametrize("use_short_path", (False, True)) @pytest.mark.parametrize("is_sys", (False, True)) From 5acb8f4f4b44998d22448866e196ba4026cd4dfd Mon Sep 17 00:00:00 2001 From: Tal Hadad Date: Thu, 15 May 2025 19:35:06 +0300 Subject: [PATCH 6/7] fix windows support of the integration test again --- integration_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration_test.py b/integration_test.py index 5ec80ee5..f3e5d59b 100644 --- a/integration_test.py +++ b/integration_test.py @@ -63,7 +63,7 @@ def test_relative_header_2(tmpdir, inv, source_relative): if source_relative and not inv: assert '#line 8 "test.h"' in stdout else: - assert f'#line 8 "{pathlib.PosixPath(tmpdir)}/test.h"' in stdout + assert f'#line 8 "{pathlib.PurePosixPath(tmpdir)}/test.h"' in stdout @pytest.mark.parametrize("is_sys", (False, True)) @pytest.mark.parametrize("inv", (False, True)) @@ -86,7 +86,7 @@ def test_relative_header_3(tmpdir, is_sys, inv, source_relative): if source_relative and not inv: assert '#line 8 "test_subdir/test.h"' in stdout else: - assert f'#line 8 "{pathlib.PosixPath(test_subdir)}/test.h"' in stdout + assert f'#line 8 "{pathlib.PurePosixPath(test_subdir)}/test.h"' in stdout @pytest.mark.parametrize("use_short_path", (False, True)) @pytest.mark.parametrize("is_sys", (False, True)) From bfecfeea50610fb4fa045bf9be42dcbeaa26b992 Mon Sep 17 00:00:00 2001 From: Tal Hadad Date: Thu, 15 May 2025 19:42:21 +0300 Subject: [PATCH 7/7] fix again --- integration_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration_test.py b/integration_test.py index f3e5d59b..4fe0129b 100644 --- a/integration_test.py +++ b/integration_test.py @@ -63,7 +63,7 @@ def test_relative_header_2(tmpdir, inv, source_relative): if source_relative and not inv: assert '#line 8 "test.h"' in stdout else: - assert f'#line 8 "{pathlib.PurePosixPath(tmpdir)}/test.h"' in stdout + assert f'#line 8 "{pathlib.PurePath(tmpdir).as_posix()}/test.h"' in stdout @pytest.mark.parametrize("is_sys", (False, True)) @pytest.mark.parametrize("inv", (False, True)) @@ -86,7 +86,7 @@ def test_relative_header_3(tmpdir, is_sys, inv, source_relative): if source_relative and not inv: assert '#line 8 "test_subdir/test.h"' in stdout else: - assert f'#line 8 "{pathlib.PurePosixPath(test_subdir)}/test.h"' in stdout + assert f'#line 8 "{pathlib.PurePath(test_subdir).as_posix()}/test.h"' in stdout @pytest.mark.parametrize("use_short_path", (False, True)) @pytest.mark.parametrize("is_sys", (False, True))