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

Add check for absolute path of config file #1276

Merged

Conversation

KipHamiltons
Copy link
Contributor

@KipHamiltons KipHamiltons commented May 7, 2020

#1071
Added absolute path capability for specifying config file.
This is my first time addressing an issue with a GitHub commit - if I have screwed up anything, please let me know! :)

@@ -88,7 +88,9 @@ bool ConfigFile::Init(OptionsParser* options) {
// loading the default configuration file.
if (filename == "") return true;

filename = CommandLine::BinaryDirectory() + "/" + filename;
if (filename.at(0) != '/') {
Copy link
Contributor

@ddobbelaere ddobbelaere May 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix will work on Unix-like operating systems, but seems to leave Windows (where absolute paths tend to start with C:\, D:\, etc) users in the cold.

Copy link
Contributor Author

@KipHamiltons KipHamiltons May 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a preprocessor directive to check for windows, then check for a colon in that path. I don't have a way to whether the windows section is robust though.
Thanks for pointing that out though! I forgot that this project is for windows too!

@ddobbelaere
Copy link
Contributor

ddobbelaere commented May 8, 2020

Now that we support C++17, I think https://stackoverflow.com/a/43278300 is more robust and prettier (probably there exist corner cases where the second character of an absolute path on Windows is not a colon). Hmm, there is even a function std::filesystem::absolute to convert any path to its absolute form, see https://en.cppreference.com/w/cpp/filesystem/absolute, but actually we cannot use it as we have to reference w.r.t. the binary directory and not the working directory.

On a side note: the current code throws an exception which kills the engine on Windows for single character filenames.

The compiler can't find the <filesystem>. I have no idea why not.
@KipHamiltons KipHamiltons marked this pull request as draft May 8, 2020 07:50
@ddobbelaere
Copy link
Contributor

CI on Windows systems passes. Only Android on Appveyor and Linux on Circle CI fail, probably because of this (see https://en.cppreference.com/w/cpp/filesystem):

Notes

Using this library may require additional compiler/linker options. GNU implementation prior to 9.1 requires linking with -lstdc++fs and LLVM implementation prior to LLVM 9.0 requires linking with -lc++fs

Probably @borg323 and/or @lealgo have ideas to fix this?

@borg323
Copy link
Member

borg323 commented May 8, 2020

Just a quick hint for now, this should probably be handled in src/utils/filesystem.posix.cc and src/utils/filesystem.win32.cc.

@KipHamiltons
Copy link
Contributor Author

KipHamiltons commented May 8, 2020

I initially pushed that commit because I had no idea why my compiler couldn't find <filesystem>, then I realised that I was using the wrong compiler just after I pushed.

Now that I can actually test my code, I am getting a segfault whenever I call the std::filesystem::path constructor.

for example, just having the line std::filesystem::path test = ""; in there, without using the variable creates a segfault a bit later, when the ParseFile is returning true (I didn't add a --config option).

Just a quick hint for now, this should probably be handled in src/utils/filesystem.posix.cc and src/utils/filesystem.win32.cc.

I'll have a go at porting it over (I said 'now' before, but I realise now that this isn't a copy-paste job to move it over)

@ddobbelaere
Copy link
Contributor

ddobbelaere commented May 8, 2020

Seems std::filesystem causes some headaches and/or is poorly supported. I wasn't aware of the OS specific files @borg323 pointed to. This seems indeed the cleanest and most consistent approach to do things there (e.g. make an "IsRelativePath" (or whatever) function with OS specific implementation, for Windows you can make use of its specific API calls).

@mooskagh
Copy link
Member

mooskagh commented May 8, 2020

Uh I was going to suggest https://en.cppreference.com/w/cpp/filesystem/path/is_absrel but see it's already being discussed. :)

@mooskagh
Copy link
Member

mooskagh commented May 8, 2020

Note that for Windows, both / and \ is allowed, and it's also allowed to omit D: part.
So technically what's absolute path in Linux is a subset of what's absolute path in Windows.

Maybe regex-based approach would work? :) Something like ^(?:\w:)?[\\/]. Although at least as of 3 years ago, support of regexes in C++ were roughly as problematic as filesystem part of STL seems to be now.

And technically speaking C:\windows/system32 is actually a valid relative path in Linux.. :)

@mooskagh
Copy link
Member

mooskagh commented May 8, 2020

How about making it similar to weights file autodiscover? Basically if the value is <default>, search for Lc0.config in the directory of binary. Otherwise just use the path (relative to cwd if it's relative).

@KipHamiltons
Copy link
Contributor Author

I have used the check for first character / in the posix filesystem, and let the windows API decide about the windows path, as per https://stackoverflow.com/a/5377662/11108223 - although I am not sure if I need to #include <shlwapi.h> on the windows file.

How about making it similar to weights file autodiscover? Basically if the value is , search for Lc0.config in the directory of binary. Otherwise just use the path (relative to cwd if it's relative).

I have retained this functionality I think, by not messing with how it works currently for the most part.

I really appreciate all of your help everyone (not that this is necessarily done). Please keep the feedback coming - I am really enjoying my first open source experience :)

@lealgo
Copy link
Contributor

lealgo commented May 9, 2020

IMO the main issue here is that the current functionality (in the release) is confusing: the config file can only reside in a path that is relative to the directory where the binary is located. This is a very weird convention. Normally paths are either absolute or relative to the current working dir. So I like @mooskagh's idea.

@KipHamiltons
Copy link
Contributor Author

KipHamiltons commented May 9, 2020

Ahh I think I understand how that is different to what I have done/what happens at the moment. Do you want me to go full steam ahead on that @lealgo ?

EDIT: Also, I have no idea how to show the linker where to find the windows API method which I used to determine if the path is relative. Directions would be very appreciated, as I have very little experience with building projects (university doesn't seem to think its so important lol...)

@mooskagh
Copy link
Member

mooskagh commented May 9, 2020

Yeah (unless someone objects) I think having it only search in the directory of the binary if it's "<default>" is good enough to be implemented. :)

That way we'll also be able to search multiple locations by default in future, which is useful for linux (i.e. lc0.config in the directory of the binary, then '~/.config/lc0/lc0.config, then /etc/lc0.config, then ./lc0.config`).

@KipHamiltons KipHamiltons marked this pull request as ready for review May 9, 2020 23:58
@ddobbelaere
Copy link
Contributor

ddobbelaere commented May 10, 2020

The current solution comes forward to what @mooskagh suggested, allows users to specify an absolute path and treats relative paths (except the default config filename itself, but this can be overruled to use the file in the working dir by using ./lc0.config) w.r.t. the working directory, which is more logical. LGTM.

Nit: there are still some stale unneeded #include statements lingering.

@KipHamiltons
Copy link
Contributor Author

Nit: there are still some stale unneeded #include statements lingering.

Well spotted! cheers!

filename = CommandLine::BinaryDirectory() + "/" + filename;
// Check to see if we are using the default config file or not.
const bool using_default_config =
filename == std::string(kDefaultConfigFile);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to have a separate value for default behaviour, like "<default>" or "<auto>" (which still will read $LC0_DIRECTORY/lc0.config), similarly to what we have for weights file (there we have "<autodiscover>").

Otherwise when run like ./lc0 -c lc0.cfg it will search in the current directory, while for ./lc0 -c lc0.config it will search in the directory of the binary, which is a confusing inconsistency.

Also in future we'll try several locations by default (possibly with different file names, not only directories, e.g. /etc/lc0.cfg vs ~/.lc0rc), and it's more logical if the parameter doesn't have file name in it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made changes along these lines. Let me know if this is what you were thinking 🙂

@@ -42,7 +42,7 @@ const OptionId kConfigFileId{
"Path to a configuration file. The format of the file is one command line "
"parameter per line, e.g.:\n--weights=/path/to/weights",
'c'};
const char* kDefaultConfigFile = "lc0.config";
const char* kDefaultConfigFile = "<default>";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for nitpicking, but I suggest moving both constants here:

const char* kDefaultConfigFile = "lc0.config";
const char* kDefaultConfigFileParam = "<default>";

(or if it's one, better it be the filename and not the option value)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a problem. Do these changes match what you were thinking?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@mooskagh mooskagh merged commit a3b38f9 into LeelaChessZero:master May 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants