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

MSYS / cygwin symlinks #246

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

hakonhagland
Copy link
Contributor

This fixes issue #213 on my machine.

@plicease plicease self-requested a review January 22, 2021 18:07
@hakonhagland
Copy link
Contributor Author

Also note that MSYS2 can emulate symbolic links in at least three ways (see this blog for more information). For example:

$ touch a.txt
# Create a symbolic link:
$ MSYS=winsymlinks:nativestrict ln -s a.txt b.txt
# Create a .lnk shortcut file:
$ MSYS=winsymlinks ln -s a.txt c.txt
# Emulate symbolic links by copying the file:
$ MSYS= ln -s a.txt d.txt
$ ls -l
total 4.0K
-rw-r--r-- 1 hakon hakon 0 Jan 22 20:54 a.txt
lrwxrwxrwx 1 hakon hakon 5 Jan 22 20:54 b.txt -> a.txt
lrwxrwxrwx 1 hakon hakon 5 Jan 22 20:55 c.txt -> a.txt
-rw-r--r-- 1 hakon hakon 0 Jan 22 20:54 d.txt

Maybe we also need to check the content of the MSYS environment variable to distinguish between the cases?

@hakonhagland
Copy link
Contributor Author

MSYS=winsymlinks:nativestrict ln -s a.txt b.txt

I added a new commit that I hope is more accurate, in that it tests for this case specifically on Cygwin and MSYS2

@plicease plicease changed the title Possible fix for issue #213 MSYS / cygwin symlinks Apr 3, 2021
@plicease plicease added 💣MSWin32 Windows is a weird best 🚉Platform Specific Often Windows lol, but could be something else labels Apr 3, 2021
compilet-Y7gS9.c Outdated Show resolved Hide resolved
if ($nativesymlink) {
# NOTE: On linux, it is OK to create broken symlinks, but it is not allowed on
# windows MSYS2/Cygwin when nativestrict is used.
die "cannot create native symlink to nonexistent file $target on $^O";
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure why this is necessary? Trying to create the broken symlink already fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Trying to create the broken symlink already fails.

I think there were two things I was trying to do here. First, if the target does exist relative to the source we still need to temporarily create an empty file relative to the destination, see line 91 below, since the file might not be copied by File::Find::find() yet. Second I was trying to provide some more context for the error message, and maybe document in the code that we actually have thought about the issue, hopefully making the code more maintainable.

To solve the issue with the destination, I create a temporarily empty file relative to the destination, but in doing this the symlink call on line 97 will no longer fail. I think that is one reason why I included the check here..

$dst->parent->child($target)->touchpath;
}
}
my $curdir = Path::Tiny->cwd;
Copy link
Member

Choose a reason for hiding this comment

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

For AB I usually use File::chdir to avoid clutter of tracking temporary directory changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, I will update the code to use File::chdir instead.

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
my $curdir = Path::Tiny->cwd;

line can be removed now.

lib/Alien/Build/Util.pm Outdated Show resolved Hide resolved
}
my $curdir = Path::Tiny->cwd;
# CD into the directory, such that symlink will work on MSYS2
chdir $dst->parent or die "could not chdir to $src->parent : $!";
Copy link
Member

Choose a reason for hiding this comment

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

I would like more illumination on why we are changing into the destination directory?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For a relative target, the symlink call will fail if the target does not exist. The existence check is done relative to the current directory (tested this now).

@plicease
Copy link
Member

plicease commented Apr 3, 2021

This patch seems invasive for a $^O eq 'msys' which is an unofficial fork of Perl which as far as I can tell is only really useful for running autoconf.

}
}
if ($nativesymlink) {
$dst->parent->child($target)->touchpath;
Copy link
Member

Choose a reason for hiding this comment

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

I guess this is assuming that the target will later be updated as part of the copy? There is a corner case here though when the link really should be broken at the destination because of relative links, will leave an empty file instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will leave an empty file instead.

That should not happen since we do the check of existence relative to the source at line 83. So if the target does not exist relative to the source, the code dies at line 87.

Be more specific/accurate when testing the cases that cannot create broken
symlinks.
@@ -65,7 +80,37 @@ sub _mirror
{ unlink "$dst" }
my $target = readlink "$src";
Alien::Build->log("ln -s $target $dst") if $opt->{verbose};
symlink($target, $dst) || die "unable to symlink $target => $dst";
Copy link
Member

Choose a reason for hiding this comment

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

I would like to keep this simplified behavior when $^O is not msys or cygwin.

Comment on lines +50 to +53
my $newdir = $tmp1->child("lib");
my $savedir = Path::Tiny->cwd;
# CD into the the $newdir such that symlink will work on MSYS2
chdir $newdir->stringify or die "unable to chdir to $newdir: $!";
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
my $newdir = $tmp1->child("lib");
my $savedir = Path::Tiny->cwd;
# CD into the the $newdir such that symlink will work on MSYS2
chdir $newdir->stringify or die "unable to chdir to $newdir: $!";
local $CWD = $tmp1->child("lib")->stringify;

}
chdir $savedir or die "unable to chdir to $savedir: $!";
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
chdir $savedir or die "unable to chdir to $savedir: $!";

@plicease
Copy link
Member

I think this is close. Aside from a couple of very minor nits mentioned above, I would like to keep the original simple one-statement call to symlink on UNIX and only delve into the msys/cygwin logic if we are on that platform.

@hakonhagland
Copy link
Contributor Author

hakonhagland commented Jun 30, 2021

Thanks for the comments! In the meantime I have found some more accurate information about the behavior of symlinks on Windows when working on this issue. Unfortunately it is quite complicated. The plan is to come back to this PR later and update it..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💣MSWin32 Windows is a weird best 🚉Platform Specific Often Windows lol, but could be something else
Development

Successfully merging this pull request may close these issues.

2 participants