Bazel: Remove maximum path length limitation on Windows

Created on 25 May 2020  路  10Comments  路  Source: bazelbuild/bazel

Description of the problem / feature request:

It will be nice to have a command line option to remove the maximum path length limitation on Windows. Windows has allowed to remove the path length limitation on Windows 10 Anniversary update. However, bazel still works with path length restriction. I am thinking of having a command line option --remove-path-length-limit which makes bazel to work without the limitation

Feature requests: what underlying problem are you trying to solve with this feature?

I am trying to build Tensorflow with --dynamic_mode=fully and get this error.

ERROR: file 'tensorflow/utils.dll' is generated by these conflicting actions:
Label: //tensorflow:libtensorflow_framework.so.2.2.0
RuleClass: cc_binary rule
Configuration: a2bfe99001a9a169e32dedfd9726eb6b74459ec5cb6bf69de2a3f0c887ba9f19
Mnemonic: Symlink
Action key: 61e799b1ac91eabec3c28dfd56b3272b5cb7609a10ef471329252741a303302f
Progress message: Copying Execution Dynamic Library
PrimaryInput: File:[[<execution_root>]bazel-out/x64_windows-opt/bin]tensorflow/core/grappler/clusters/utils.dll, File:[[<execution_root>]bazel-out/x64_windows-opt/bin]tensorflow/core/grappler/costs/utils.dll
PrimaryOutput: File:[[<execution_root>]bazel-out/x64_windows-opt/bin]tensorflow/utils.dll
ERROR: Analysis of target '//tensorflow/tools/pip_package:build_pip_package' failed; build aborted: for tensorflow/utils.dll, previous action: action
'Copying Execution Dynamic Library', attempted action: action 'Copying Execution Dynamic Library'

I think it is not an error with Tensorflow because --dynamic_mode=fully is running fine on Linux. I think this line causes the problem
https://github.com/bazelbuild/bazel/blob/5f083b8f5a073a3427d575aa54eac5b779226708/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java#L1055
Since SymlinkAction can not create a symlink whose name is too long, it has to copy the file and causes the problem.

What operating system are you running Bazel on?

Windows 10

Have you found anything relevant by searching the web?

I found an issue which this feature could solve the problems.

https://github.com/bazelbuild/bazel/issues/8400
In fact, I think this is the main reason why building dll with bazel is not so easy

Any other information, logs, or outputs that you want to share?

I think adding this feature could allow bazel to build dll on Windows easier.

area-Windows windows team-XProduct untriaged

All 10 comments

Hi @vnvo2409 , the Windows path limit is not the cause of the problem you described. The real cause is how dynamic library (DLL) works on Windows.

So, on Windows, the binary file can only find DLLs in certain system directories, PATH, and the directory of the binary itself. To make DLLs available at runtime, Bazel chooses to copy those DLLs to the directory of the binary. But unfortunately, in TensorFlow there are targets with the same name in different packages. In your case, it's the two utils.dll. Besides, there are some other issues for dynamic linking on Windows, like symbols visibility is off by default. In general, we don't recommend to use --dynamic_mode=full on Windows.

As for the long path issue, Bazel actually did many improvements on that. It can handle long paths in most of places. But because the MSVC compiler still doesn't support long path, we recommend to use a short output directory.

And we recently added support for creating symlinks, check --windows_enable_symlinks

For more information, check https://docs.bazel.build/versions/master/windows.html#best-practices

@meteorcloudy
Thank you for your reponse.

It seems that the lastest release does not support --windows_enable_symlinks yet so I will wait to the next release.

About the DLL, I think that a mechanism like set PATH=c:\MyDLLFolder;%PATH% would do the trick since we have already known about the location of the dependent dll thank to the name of deps, and set only affects current shell. Furthermore, we could use SetDllDirectoryW to set the dll directory and after finish cc_binary we could call SetDllDirectoryW(null) to avoid clash between two dlls with the same name.

Could we have an option to enable this behavior ? If it is ok, I am very happy to work on it.

@vnvo2409

I think that a mechanism like set PATH=c:MyDLLFolder;%PATH% would do the trick

I don't think this will solve the problem. Because there the binary actually depends on two "utils.dll", which are completely different things. That means depending on which one appears first in PATH, the symbols in the other one will not be found. They only way to fix it is to give different names for those two DLLs. We can 1) of course, rename the targets, 2) make Bazel output the DLL name with a hash, eg utils-${hash of package}.dll. But this requires tweak of the C++ rules. Please tell me if you want to work it. ;)

Here is a doc about how dynamic linking work on Windows in Bazel.
https://docs.google.com/document/d/1ZK4f84wype5NsZ7ltOUqvyFr7eKOIf4Wd-DrU6HCBkA/edit?usp=sharing

@meteorcloudy
I undestand the problems now. I will read the doc and let you know later if I could work on it or not. I am a GSoC student of Tensorflow this year and in my project, I think I will need TF to build dynamically to get this feature work on Windows ( It's just my assumption though ) Let me discuss with my mentor and I will tell you later. Thank you.

In addition, the solution that make Bazel output the DLL name with a hash, eg utils-${hash of package}.dll seems very good. I would like to know how the hash will be calculated. I think it will be calculated by the dll's path since the dll itself and the c++ rule both know the path, right ?

@meteorcloudy
I can work on it. Your solution is using a .lib file as an interface library and a .DEF file to actually point to the .dll. If I understand correctly, my work now is to rename the dll and add the name to a generated .DEF file. Please correct me if I am wrong

I would like to know how the hash will be calculated.

I think the hash should be at calculated based on RepositoryName + the package path the DLL belongs to. That should make the name unique and deterministic across the build.

Your solution is using a .lib file as an interface library and a .DEF file to actually point to the .dll. If I understand correctly, my work now is to rename the dll and add the name to a generated .DEF file. Please correct me if I am wrong

That's exactly what I mean! So glad you figured that out yourself!

BTW, you can file another issue to track the progress if you want. 馃槈

@meteorcloudy
Could you give me some hints about where to start since the code base is very large.
Here is the link to the new issue https://github.com/bazelbuild/bazel/issues/11515
Thank you

That sounds good!

Was this page helpful?
0 / 5 - 0 ratings