Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clang++ failed create output file on windows if path more 247 chars #478

Closed
leanid opened this issue Aug 3, 2017 · 12 comments
Closed

clang++ failed create output file on windows if path more 247 chars #478

leanid opened this issue Aug 3, 2017 · 12 comments
Assignees
Labels

Comments

@leanid
Copy link

leanid commented Aug 3, 2017

Description

clang++.exe failed to compile file on windows 10 if output object file path length more then 247 chars on my machine. I prepare minimal test case. Also I try to enable LongPathSupport but it not influence on clang++.exe.

Minimal test case:

  1. put main.cpp - empty file into deep deep path folder
  2. call clang++.exe from last NDK to produce objective file
  3. add to output objective file name more charecters and try again
  4. see result if output path more then 247 chars got error.

Environment Details

command line:

C:\Users\l_chayka>d:\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++ -c D:/j/client/WoTBlitzAndroid/WotBlitz/build/intermediates/ndkBuild/debug/obj/local/x86/objs-debug/DavaNetworkServices/__/__/__/dava.framework/Modules/MemoryProfilerService/Sources/MemoryProfilerService/Private/main.cpp -o D:/j/client/WoTBlitzAndroid/WotBlitz/build/intermediates/ndkBuild/debug/obj/local/x86/objs-debug/DavaNetworkServices/__/__/__/dava.framework/Modules/MemoryProfilerService/Sources/MemoryProfilerService/Private/M11111111111111111111111111111111111.o

C:\Users\l_chayka>d:\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++ -c D:/j/client/WoTBlitzAndroid/WotBlitz/build/intermediates/ndkBuild/debug/obj/local/x86/objs-debug/DavaNetworkServices/__/__/__/dava.framework/Modules/MemoryProfilerService/Sources/MemoryProfilerService/Private/main.cpp -o D:/j/client/WoTBlitzAndroid/WotBlitz/build/intermediates/ndkBuild/debug/obj/local/x86/objs-debug/DavaNetworkServices/__/__/__/dava.framework/Modules/MemoryProfilerService/Sources/MemoryProfilerService/Private/M111111111111111111111111111111111112.o
error: unable to open output file
      'D:/j/client/WoTBlitzAndroid/WotBlitz/build/intermediates/ndkBuild/debug/obj/local/x86/objs-debug/DavaNetworkServices/__/__/__/dava.framework/Modules/MemoryProfilerService/Sources/MemoryProfilerService/Private/M111111111111111111111111111111111112.o':
      'No such file or directory'
1 error generated.

C:\Users\l_chayka>
  • Pkg.Desc = Android NDK Pkg.Revision = 15.1.4119039
  • directly call compiler (minimal exemple)
  • Host OS: Windows 10 64 bit
  • Compiler: Clang++.
@DanAlbert
Copy link
Member

DanAlbert commented Aug 3, 2017

I assume you rebooted after changing that registry key? (It should only require a new run of clang, but ¯\_(ツ)_/¯)

Assuming that is the case: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath

Only a small family of functions is affected by that registry key. @stephenhines @pirama-arumuga-nainar: I assume that mingw is using multibyte strings. Any idea if there's a way to get it moved over to wide strings? (Or can we build Clang with msvc in the new system?)

@leanid
Copy link
Author

leanid commented Aug 3, 2017

Yes, I rebooted after change registry value, nothing happened, and after that start counting how many characters in path and it was not MAX_PATH limit of 260 only 248. Also this bug present in last windows build of clang++-4.0.1 too(just checked), maybe report there.

@leanid
Copy link
Author

leanid commented Aug 4, 2017

Found problem in clang in path convertion. If input file path not fit into MAX_PATH then clang use on windows long path names started from \\\\?\\ all directory separators converted from unix / to windows \\ BUT the first one NOT!
In my previous example resulted tmp path name converted inside clang.exe to:

\\\\?\\D:/j\\client\\WoTBlitzAndroid\\WotBlitz\\build\\intermediates\\ndkBuild\\debug\\obj\\local\\x86\\objs-debug\\DavaNetworkServices\\__\\__\\__\\dava.framework\\Modules\\MemoryProfilerService\\Sources\\MemoryProfilerService\\Private\\M111111111111111111111111111111111112.o-54d9ec6

look at first after D: should be:

\\\\?\\D:\\j\\client\\WoTBlitzAndroid\\WotBlitz\\build\\intermediates\\ndkBuild\\debug\\obj\\local\\x86\\objs-debug\\DavaNetworkServices\\__\\__\\__\\dava.framework\\Modules\\MemoryProfilerService\\Sources\\MemoryProfilerService\\Private\\M111111111111111111111111111111111112.o-54d9ec6

incoming parameter in command line was:

 D:/j/client/WoTBlitzAndroid/WotBlitz/build/intermediates/ndkBuild/debug/obj/local/x86/objs-debug/DavaNetworkServices/__/__/__/dava.framework/Modules/MemoryProfilerService/Sources/MemoryProfilerService/Private/main.cpp -o D:/j/client/WoTBlitzAndroid/WotBlitz/build/intermediates/ndkBuild/debug/obj/local/x86/objs-debug/DavaNetworkServices/__/__/__/dava.framework/Modules/MemoryProfilerService/Sources/MemoryProfilerService/Private/M111111111111111111111111111111111112.o

All directory separators in unix style. And after internal clang conversion only first not changed.

@leanid
Copy link
Author

leanid commented Aug 4, 2017

look at the: llvm/lib/Support/Path.cpp:427 (current trunk version)
look at START FIX and END FIX

void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
            const Twine &b, const Twine &c, const Twine &d) {
  SmallString<32> a_storage;
  SmallString<32> b_storage;
  SmallString<32> c_storage;
  SmallString<32> d_storage;

  SmallVector<StringRef, 4> components;
  if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage));
  if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage));
  if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage));
  if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));

  for (auto &component : components) {
    bool path_has_sep =
        !path.empty() && is_separator(path[path.size() - 1], style);
    bool component_has_sep =
        !component.empty() && is_separator(component[0], style);
    bool is_root_name = has_root_name(component, style);

    if (path_has_sep) {
      // Strip separators from beginning of component.
      size_t loc = component.find_first_not_of(separators(style));
      StringRef c = component.substr(loc);

      // Append it.
      path.append(c.begin(), c.end());
      continue;
    }

    if (!component_has_sep && !(path.empty() || is_root_name)) {
      // Add a separator.
      path.push_back(preferred_separator(style));
    }
// START FIX
    else if (component_has_sep && component.size() == 1)
    {
	// component itself is a separator '/' on windows after split: [c:/j/file] ->[{c:}, {/}, {j}, {/file}]
        // we have to change '/' into '\\' on windows on path start with "\\\\?\\"
	path.push_back(preferred_separator(style));
	continue;
    }
// END FIX
    path.append(component.begin(), component.end());
  }
}

@pirama-arumuga-nainar
Copy link
Collaborator

@leanid: Thanks for the diagnosis. It is indeed correct. Only suggestion would be to defensively invoke the fix only on Windows and only when path[-1] is a :. I'll put together a patch for upstream review (unless you want to contribute yourself, considering you did pretty much did the entire investigation).

@leanid
Copy link
Author

leanid commented Aug 7, 2017

Nice, please do the patch to upstream yourself.

@pirama-arumuga-nainar
Copy link
Collaborator

https://reviews.llvm.org/rL311382 is the commit from upstream. We'll cherry-pick it to r16 (hopefully in one of the betas).

@DanAlbert DanAlbert added the clang label Oct 3, 2017
@DanAlbert
Copy link
Member

If this didn't make r16 then it's in r17 since that has another update.

@imReker
Copy link

imReker commented May 29, 2018

Problem seems not solved totally in r17.
In my case, some long path libraries can be built successfully with r17 (which failed on r16 or earlier due to this issue), but still get error on another library in same project.

[armeabi-v7a] Compile thumb  : ancillary <= fd_recv.c
[armeabi-v7a] Compile thumb  : ancillary <= fd_send.c
[armeabi-v7a] StaticLibrary  : libancillary.a
D:/android-sdk/ndk-bundle/build//../toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-ar: E:/AndroidStudioProjects/Project/Client-Android-Demo/core/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/objs-debug/ancillary/E_/AndroidStudioProjects/Project/Client-Android-Demo/core/src/main/jni/android/Tester/__/libancillary/__/__/depends/libancillary/fd_recv.o: No such file or directory
make: *** [E:/AndroidStudioProjects/Project/Client-Android-Demo/core/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libancillary.a] Error 1

The fd_recv.o is built successfully (I've checked the file, it exist in correct place) but can't be found in linking.

@pirama-arumuga-nainar
Copy link
Collaborator

The path is longer than 260 characters, but the failure is from arm-linux-androideabi-ar. @DanAlbert should the build system be prepending long paths with '\?' when invoking tools?

@imReker
Copy link

imReker commented Jun 4, 2018

@pirama-arumuga-nainar Any update? Should I open a new issue on this problem?

@pirama-arumuga-nainar
Copy link
Collaborator

IIUC, the failure is when invoking arm-linux-androideabi-ar and not clang itself. If that's the case, then open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants