Skip to content

Commit 57d8b93

Browse files
committed
[build] Don't use ls(1) to find JDK paths
Fixes: dotnet/android#1493 On some machines, `make prepare` fails: build-tools/scripts/jdk.mk:130: *** missing separator. Stop. make: *** [prepare-external] Error 2 Eventually, we "found" the "cause": This make fragment: $(shell ls -dtr $(_DARWIN_JDK_FALLBACK_DIRS) | sort | tail -1) was dying a terrible horrible no good death: _DARWIN_JDK_ROOT=/Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkin/sh: 49m: command not found [Turns Out™][0], **ls**(1) should be *avoided*, as its output is *unsafe* (I'm not sure *why*, and I'm not able to repro the above failure on my machine, but it's *clearly* bad). [0]: http://mywiki.wooledge.org/ParsingLs Why are we using **ls**(1)? To sort by timestamp, via `ls -dtr`. What's the recommended replacement? > If you truly need a list of all the files in a directory in order > by mtime so that you can process them in sequence, switch to perl, > and have your perl program do its own directory opening and sorting LOL? Which brings us to the solution: we don't want to use Perl -- we *want* something plausibly cross-platform -- so let's use our existing cross-platform dependency: MSBuild! Add a new `<JdkDirectoryFinder/>` task, to which we provide a "JDKs Root" directory -- the directory which contains JDKs -- and the `<JdkDirectoryFinder/>` task will open that directory, sort the contents, skip the "out of version range" JDK versions (`$(JI_JDK_MAX)`; commit 55c56f7), and return the "best" JDK root directory from those available.
1 parent b19bc60 commit 57d8b93

File tree

7 files changed

+207
-19
lines changed

7 files changed

+207
-19
lines changed

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ xa-all: $(PACKAGES) $(XA_INTEGRATION_OUTPUTS)
5353

5454
run-all-tests: run-tests run-test-jnimarshal run-test-generator-core run-ptests
5555

56-
prepare:: prepare-external
56+
prepare:: prepare-bootstrap prepare-external
57+
58+
prepare-bootstrap:
59+
$(MSBUILD) $(MSBUILD_FLAGS) src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj
5760

5861
prepare-external: $(PACKAGES) $(NUNIT_CONSOLE)
5962
git submodule update --init --recursive
@@ -64,8 +67,8 @@ clean:
6467
-rm src/Java.Runtime.Environment/Java.Runtime.Environment.dll.config
6568

6669
include build-tools/scripts/mono.mk
67-
include build-tools/scripts/jdk.mk
6870
include build-tools/scripts/msbuild.mk
71+
include build-tools/scripts/jdk.mk
6972

7073
$(PACKAGES) $(NUNIT_CONSOLE):
7174
nuget restore

build-tools/scripts/jdk.mk

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,6 @@ JI_JAR_PATH = jar
3232
JI_JDK_BIN_PATH = $(dir $(shell which java))
3333

3434

35-
# Filter on <= JI_MAX_JDK
36-
ifneq ($(JI_MAX_JDK),)
37-
_VERSION_MAX := | awk '$$1 <= $(JI_MAX_JDK)'
38-
endif #JI_MAX_JDK
39-
40-
# Sort numerically on version numbers with `sort -n`, filtering on $(JI_MAX_JDK) if needed
41-
# Replace each line so it starts with a number (sed 's/...'\1 &/), sort on the leading number, then remove the leading number.
42-
# Grab the last path name printed.
43-
_VERSION_SORT := sed 's/[^0-9]*\([0-9.]*\)/\1 &/' $(_VERSION_MAX) | sort -n | sed 's/^[0-9.]* //g' | tail -1
44-
4535
ifeq ($(OS),Darwin)
4636

4737
_MONO_BITNESS = $(shell file `which $(word 1, $(RUNTIME))` | awk 'BEGIN { val = "32-bit" } /64-bit/ { val = "64-bit" } END { print val; }')
@@ -51,6 +41,12 @@ ifeq ($(_MONO_BITNESS),32-bit)
5141
JI_JVM_PATH = /System/Library/Frameworks/JavaVM.framework/JavaVM
5242
endif # 32-bit
5343

44+
# $(call FindJdkDirectory,dir)
45+
define FindJdkDirectory
46+
$(MSBUILD) $(MSBUILD_FLAGS) build-tools/scripts/jdk.targets /nologo /v:minimal /t:GetPreferredJdkRoot \
47+
/p:JdksRoot="$(1)" $(if $(JI_MAX_JDK),"/p:MaximumJdkVersion=$(JI_MAX_JDK)")
48+
endef
49+
5450
# Darwin supports three possible search locations:
5551
#
5652
# 1. `/Library/Java/JavaVirtualMachines/jdk*`
@@ -62,7 +58,7 @@ endif # 32-bit
6258
#
6359
# 3. A "locally" hosted .pkg, in case Xcode.app isn't installed.
6460

65-
_DARWIN_JDK_FALLBACK_DIRS = $(wildcard /Library/Java/JavaVirtualMachines/jdk*)
61+
_DARWIN_JDK_FALLBACK_ROOT = $(wildcard /Library/Java/JavaVirtualMachines)
6662
_DARWIN_JDK_JNI_INCLUDE_DIR = Contents/Home/include
6763
_DARWIN_JDK_JNI_OS_INCLUDE_DIR = $(_DARWIN_JDK_JNI_INCLUDE_DIR)/darwin
6864

@@ -77,8 +73,8 @@ _LOCAL_JDK_HEADERS = LocalJDK/System/Library/Frameworks/JavaVM.fr
7773
# Ancient source for (3)
7874
_APPLE_JDK6_URL = http://adcdownload.apple.com/Developer_Tools/java_for_os_x_2013005_developer_package/java_for_os_x_2013005_dp__11m4609.dmg
7975

80-
ifneq ($(_DARWIN_JDK_FALLBACK_DIRS),)
81-
_DARWIN_JDK_ROOT := $(shell ls -dtr $(_DARWIN_JDK_FALLBACK_DIRS) | $(_VERSION_SORT))
76+
ifneq ($(_DARWIN_JDK_FALLBACK_ROOT),)
77+
_DARWIN_JDK_ROOT := $(shell $(call FindJdkDirectory,$(_DARWIN_JDK_FALLBACK_ROOT)) | tr -d '[[:space:]]')
8278
JI_JDK_BIN_PATH = $(_DARWIN_JDK_ROOT)/Contents/Home/bin
8379
JI_JAVAC_PATH = $(_DARWIN_JDK_ROOT)/Contents/Home/bin/javac
8480
JI_JAR_PATH = $(_DARWIN_JDK_ROOT)/Contents/Home/bin/jar
@@ -117,7 +113,7 @@ ifeq ($(OS),Linux)
117113
# This is for all linux distributions with which and java installed
118114
_DEFAULT_LINUX_JAVA_ROOT = $(shell java -XshowSettings:properties -help 2>&1 | grep java.home | sed 's/^.*java.home = //g')/../
119115
_DEFAULT_LINUX_JAVA_INCLUDE_DIRS = $(_DEFAULT_LINUX_JAVA_ROOT)/include/
120-
_LINUX_JAVA_FALLBACK_DIRS = /usr/lib/jvm/java*
116+
_LINUX_JAVA_FALLBACK_ROOT = $(wildcard /usr/lib/jvm)
121117
_LINUX_JAVA_JNI_INCLUDE_DIR = include
122118
_LINUX_JAVA_ROOT = $(_DEFAULT_LINUX_JAVA_ROOT)
123119
_LINUX_JAVA_ARCH_64 = amd64
@@ -130,8 +126,8 @@ _DESKTOP_JAVA_INCLUDE_DIRS = $(wildcard $(JAVA_HOME)/include)
130126
_LINUX_JAVA_ROOT = $(JAVA_HOME)
131127
endif # No default Java location, $JAVA_HOME check
132128

133-
ifeq ($(wildcard $(_DESKTOP_JAVA_INCLUDE_DIRS)),)
134-
LATEST_JDK := $(shell ls -dtr $(_LINUX_JAVA_FALLBACK_DIRS) | $(_VERSION_SORT))
129+
ifeq ($(wildcard $(_LINUX_JAVA_FALLBACK_ROOT)),)
130+
LATEST_JDK := $(call FindJdkDirectory,$(_LINUX_JAVA_FALLBACK_ROOT) | tr -d '[[:space:]]')
135131
_DESKTOP_JAVA_INCLUDE_DIRS = $(LATEST_JDK)/$(_LINUX_JAVA_JNI_INCLUDE_DIR)
136132
_LINUX_JAVA_ROOT = $(LATEST_JDK)
137133
endif # No $JAVA_HOME, find the latest version

build-tools/scripts/jdk.targets

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<UsingTask TaskName="Java.Interop.BootstrapTasks.JdkDirectoryFinder" AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Java.Interop.BootstrapTasks.dll" />
4+
<Target Name="GetPreferredJdkRoot">
5+
<JdkDirectoryFinder
6+
JdksRoot="$(JdksRoot)"
7+
MaximumJdkVersion="$(MaximumJdkVersion)">
8+
<Output TaskParameter="PreferredJdkRoot" PropertyName="_JdkRoot"/>
9+
</JdkDirectoryFinder>
10+
<Message
11+
Text="$(_JdkRoot)"
12+
Importance="High"
13+
/>
14+
</Target>
15+
</Project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup Condition=" '$(TpnIncludeExternalDependencies)' == 'True' ">
4+
<!-- src/Java.Interop.BootstrapTasks/Cadenza/NaturalStringComparer.cs -->
5+
<ThirdPartyNotice
6+
Condition=" '$(TpnIncludeBuildDependencies)' == 'True' "
7+
Include="cadenza/cadenza">
8+
<LicenseText>
9+
Copyright (c) 2007, 2008 Novell, Inc.
10+
and the individuals listed on the ChangeLog entries.
11+
12+
Permission is hereby granted, free of charge, to any person obtaining
13+
a copy of this software and associated documentation files (the
14+
"Software"), to deal in the Software without restriction, including
15+
without limitation the rights to use, copy, modify, merge, publish,
16+
distribute, sublicense, and/or sell copies of the Software, and to
17+
permit persons to whom the Software is furnished to do so, subject to
18+
the following conditions:
19+
20+
The above copyright notice and this permission notice shall be
21+
included in all copies or substantial portions of the Software.
22+
23+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30+
</LicenseText>
31+
<SourceUrl>https://github.com/cadenza/cadenza/</SourceUrl>
32+
</ThirdPartyNotice>
33+
</ItemGroup>
34+
</Project>
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//
2+
// NaturalStringComparer.cs
3+
//
4+
// Authors:
5+
// Jonathan Pryor <[email protected]>
6+
//
7+
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
8+
//
9+
// Thanks to wilco` on ##[email protected].
10+
//
11+
// Permission is hereby granted, free of charge, to any person obtaining
12+
// a copy of this software and associated documentation files (the
13+
// "Software"), to deal in the Software without restriction, including
14+
// without limitation the rights to use, copy, modify, merge, publish,
15+
// distribute, sublicense, and/or sell copies of the Software, and to
16+
// permit persons to whom the Software is furnished to do so, subject to
17+
// the following conditions:
18+
//
19+
// The above copyright notice and this permission notice shall be
20+
// included in all copies or substantial portions of the Software.
21+
//
22+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26+
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27+
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28+
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29+
//
30+
31+
using System;
32+
using System.Collections.Generic;
33+
using System.Linq;
34+
using System.Text.RegularExpressions;
35+
36+
namespace Cadenza {
37+
38+
// https://github.com/cadenza/cadenza/blob/master/src/Cadenza/Cadenza/NaturalStringComparer.cs
39+
sealed class NaturalStringComparer : IComparer<string>, System.Collections.IComparer
40+
{
41+
42+
static readonly NaturalStringComparer _default = new NaturalStringComparer ();
43+
44+
private NaturalStringComparer ()
45+
{
46+
}
47+
48+
public static NaturalStringComparer Default {
49+
get {
50+
return _default;
51+
}
52+
}
53+
54+
public int Compare (string x, string y)
55+
{
56+
string left = x ?? "";
57+
string right = y ?? "";
58+
return Regex.Replace (left, @"([\d]+)|([^\d]+)",
59+
m => (m.Value.Length > 0 && char.IsDigit(m.Value[0]))
60+
? m.Value.PadLeft (System.Math.Max(left.Length, right.Length))
61+
: m.Value
62+
).CompareTo (Regex.Replace(right, @"([\d]+)|([^\d]+)",
63+
m => (m.Value.Length > 0 && char.IsDigit(m.Value[0]))
64+
? m.Value.PadLeft (System.Math.Max(left.Length, right.Length))
65+
: m.Value));
66+
}
67+
68+
int System.Collections.IComparer.Compare (object x, object y)
69+
{
70+
return Compare (
71+
x != null ? x.ToString () : "",
72+
y != null ? y.ToString () : "");
73+
}
74+
}
75+
}
76+

src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@
3737
<Reference Include="Microsoft.Build.Utilities.v4.0" />
3838
</ItemGroup>
3939
<ItemGroup>
40+
<Compile Include="Cadenza\NaturalStringComparer.cs" />
4041
<Compile Include="Java.Interop.BootstrapTasks\DownloadUri.cs" />
42+
<Compile Include="Java.Interop.BootstrapTasks\JdkDirectoryFinder.cs" />
4143
<Compile Include="Java.Interop.BootstrapTasks\JdkInfo.cs" />
4244
<Compile Include="Java.Interop.BootstrapTasks\RegistryEx.cs" />
43-
<Compile Include="Properties\AssemblyInfo.cs" />
4445
<Compile Include="Java.Interop.BootstrapTasks\SetEnvironmentVariable.cs" />
46+
<Compile Include="Properties\AssemblyInfo.cs" />
4547
</ItemGroup>
4648
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
4749
</Project>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text.RegularExpressions;
6+
7+
using Cadenza;
8+
9+
using Microsoft.Build.Utilities;
10+
using Microsoft.Build.Framework;
11+
12+
namespace Java.Interop.BootstrapTasks {
13+
14+
public class JdkDirectoryFinder : Task {
15+
16+
[Required]
17+
public string JdksRoot { get; set; }
18+
19+
public string MaximumJdkVersion { get; set; }
20+
21+
[Output]
22+
public string PreferredJdkRoot { get; set; }
23+
24+
static Regex VersionExtractor = new Regex (@"(?<version>[\d]+(\.\d+)+)", RegexOptions.Compiled);
25+
26+
public override bool Execute ()
27+
{
28+
var version = GetMaxJdkVersion ();
29+
var dirs = new List<string>();
30+
foreach (var d in Directory.EnumerateDirectories (JdksRoot)) {
31+
var n = Path.GetFileName (d);
32+
var m = version == null ? null : VersionExtractor.Match (n);
33+
Version v;
34+
35+
if (version == null || !m.Success || !Version.TryParse (m.Groups ["version"].Value, out v)) {
36+
dirs.Add (d);
37+
continue;
38+
}
39+
if (v <= version) {
40+
dirs.Add (d);
41+
}
42+
}
43+
dirs.Sort (NaturalStringComparer.Default);
44+
45+
if (dirs.Count > 0) {
46+
PreferredJdkRoot = dirs [dirs.Count-1];
47+
}
48+
49+
return true;
50+
}
51+
52+
Version GetMaxJdkVersion ()
53+
{
54+
if (string.IsNullOrEmpty (MaximumJdkVersion))
55+
return null;
56+
if (!MaximumJdkVersion.Contains (".")) {
57+
MaximumJdkVersion += ".0";
58+
}
59+
return new Version (MaximumJdkVersion);
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)