Allow building the Bazel C++ code on OpenBSD.
This change, split out of the larger PR https://github.com/bazelbuild/bazel/pull/10274, is part of the OpenBSD port in https://github.com/bazelbuild/bazel/issues/10250.
Closes #10316.
PiperOrigin-RevId: 284198941
diff --git a/src/conditions/BUILD b/src/conditions/BUILD
index faa41a4..4992880 100644
--- a/src/conditions/BUILD
+++ b/src/conditions/BUILD
@@ -47,6 +47,12 @@
)
config_setting(
+ name = "openbsd",
+ values = {"cpu": "openbsd"},
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
name = "windows",
values = {"cpu": "x64_windows"},
visibility = ["//visibility:public"],
diff --git a/src/conditions/BUILD.tools b/src/conditions/BUILD.tools
index c9160fd..51a154a 100644
--- a/src/conditions/BUILD.tools
+++ b/src/conditions/BUILD.tools
@@ -5,6 +5,12 @@
)
config_setting(
+ name = "openbsd",
+ values = {"cpu": "openbsd"},
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
name = "darwin",
values = {"cpu": "darwin"},
visibility = ["//visibility:public"],
diff --git a/src/main/cpp/BUILD b/src/main/cpp/BUILD
index 7de595d..5f8f49f 100644
--- a/src/main/cpp/BUILD
+++ b/src/main/cpp/BUILD
@@ -1,11 +1,11 @@
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
+
# Description:
# The Bazel launcher.
package(
default_visibility = ["//visibility:public"],
)
-load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
-
WIN_LINK_OPTS = [
"-DEFAULTLIB:advapi32.lib", # GetUserNameW
"-DEFAULTLIB:ole32.lib", # CoTaskMemFree
@@ -29,7 +29,11 @@
"blaze_util_posix.cc",
],
"//src/conditions:freebsd": [
- "blaze_util_freebsd.cc",
+ "blaze_util_bsd.cc",
+ "blaze_util_posix.cc",
+ ],
+ "//src/conditions:openbsd": [
+ "blaze_util_bsd.cc",
"blaze_util_posix.cc",
],
"//src/conditions:windows": [
@@ -53,6 +57,8 @@
],
"//src/conditions:freebsd": [
],
+ "//src/conditions:openbsd": [
+ ],
"//src/conditions:windows": WIN_LINK_OPTS,
"//conditions:default": [
"-lrt",
@@ -114,6 +120,8 @@
"-lprocstat",
"-lm",
],
+ "//src/conditions:openbsd": [
+ ],
"//src/conditions:windows": [
],
"//conditions:default": [
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index b9a623c..78edeeb 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -1519,21 +1519,35 @@
const blaze_util::Path jvm_path = startup_options.GetJvm();
const string server_jar_path = GetServerJarPath(archive_contents);
- const vector<string> server_exe_args = GetServerExeArgs(
- jvm_path,
- server_jar_path,
- archive_contents,
- install_md5,
- workspace_layout,
- workspace,
- startup_options);
-
- KillRunningServerIfDifferentStartupOptions(
- startup_options, server_exe_args, logging_info, blaze_server);
const blaze_util::Path server_exe =
startup_options.GetExe(jvm_path, server_jar_path);
+ vector<string> server_exe_args =
+ GetServerExeArgs(jvm_path, server_jar_path, archive_contents, install_md5,
+ workspace_layout, workspace, startup_options);
+#if defined(__OpenBSD__)
+ // When spawning the server's JVM process, we normally set argv[0] to
+ // "bazel(workspace)". On OpenBSD, doing so causes the JVM process to fail
+ // during startup; ld.so fails to find a shared library that exists in
+ // /usr/local/jdk-1.8.0/jre/lib/amd64. Setting LD_LIBRARY_PATH does not help,
+ // but setting argv[0] to the JVM binary's path
+ // (/usr/local/jdk-1.8.0/bin/java) allows the JVM process to run. The JVM
+ // process apparently tries to compute a path to where the shared libraries
+ // should be, via a relative path from the JVM executable's path -- but
+ // OpenBSD does not provide a way for a process to determine a path to its
+ // own executable, and so the JVM falls back to searching the PATH for
+ // argv[0], which of course fails when argv[0] looks like "bazel(workspace)".
+ //
+ // TODO(aldersondrive): This hack is unnecessary on FreeBSD, but the relevant
+ // OpenJDK code doesn't seem to include anything FreeBSD-specific.
+ // Investigate why and possibly remove this.
+ server_exe_args[0] = server_exe.AsNativePath();
+#endif
+
+ KillRunningServerIfDifferentStartupOptions(
+ startup_options, server_exe_args, logging_info, blaze_server);
+
const blaze_util::Path server_dir =
blaze_util::Path(startup_options.output_base).GetRelative("server");
if (IsServerMode(option_processor.GetCommand())) {
@@ -1558,7 +1572,7 @@
new blaze_util::BazelLogHandler());
blaze_util::SetLogHandler(std::move(default_handler));
- const string self_path = GetSelfPath();
+ const string self_path = GetSelfPath(argv[0]);
if (argc == 2 && strcmp(argv[1], "--version") == 0) {
PrintVersionInfo(self_path, option_processor->GetLowercaseProductName());
diff --git a/src/main/cpp/blaze_util_freebsd.cc b/src/main/cpp/blaze_util_bsd.cc
similarity index 73%
rename from src/main/cpp/blaze_util_freebsd.cc
rename to src/main/cpp/blaze_util_bsd.cc
index 72a211c..7232102 100644
--- a/src/main/cpp/blaze_util_freebsd.cc
+++ b/src/main/cpp/blaze_util_bsd.cc
@@ -12,11 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#if defined(__FreeBSD__)
+# define HAVE_PROCSTAT
+# define STANDARD_JAVABASE "/usr/local/openjdk8"
+#elif defined(__OpenBSD__)
+# define STANDARD_JAVABASE "/usr/local/jdk-1.8.0"
+#else
+# error This BSD is not supported
+#endif
+
+#if !defined(DEFAULT_SYSTEM_JAVABASE)
+# define DEFAULT_SYSTEM_JAVABASE STANDARD_JAVABASE
+#endif
+
#include <errno.h> // errno, ENAMETOOLONG
#include <limits.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
+#include <stdlib.h>
#include <string.h> // strerror
#include <sys/mount.h>
#include <sys/param.h>
@@ -26,13 +40,16 @@
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
-#include <libprocstat.h> // must be included after <sys/...> headers
+#if defined(HAVE_PROCSTAT)
+# include <libprocstat.h> // must be included after <sys/...> headers
+#endif
#include "src/main/cpp/blaze_util.h"
#include "src/main/cpp/blaze_util_platform.h"
#include "src/main/cpp/util/errors.h"
#include "src/main/cpp/util/exit_code.h"
#include "src/main/cpp/util/file.h"
+#include "src/main/cpp/util/file_platform.h"
#include "src/main/cpp/util/logging.h"
#include "src/main/cpp/util/path.h"
#include "src/main/cpp/util/port.h"
@@ -72,7 +89,8 @@
}
}
-string GetSelfPath() {
+string GetSelfPath(const char* argv0) {
+#if defined(__FreeBSD__)
char buffer[PATH_MAX] = {};
auto pid = getpid();
if (kill(pid, 0) < 0) return "";
@@ -94,6 +112,36 @@
}
procstat_close(procstat);
return string(buffer);
+#elif defined(__OpenBSD__)
+ // OpenBSD does not provide a way for a running process to find a path to its
+ // own executable, so we try to figure out a path by inspecting argv[0]. In
+ // theory this is inadequate, since the parent process can set argv[0] to
+ // anything, but in practice this is good enough.
+
+ const std::string argv0str(argv0);
+
+ // If argv[0] starts with a slash, it's an absolute path. Use it.
+ if (argv0str.length() > 0 && argv0str[0] == '/') {
+ return argv0str;
+ }
+
+ // Otherwise, if argv[0] contains a slash, then it's a relative path. Prepend
+ // the current directory to form an absolute path.
+ if (argv0str.length() > 0 && argv0str.find('/') != std::string::npos) {
+ return GetCwd() + "/" + argv0str;
+ }
+
+ // TODO(aldersondrive): Try to find the executable by inspecting the PATH.
+
+ // None of the above worked. Give up.
+ BAZEL_DIE(blaze_exit_code::BAD_ARGV)
+ << "Unable to determine the location of this Bazel executable. "
+ "Currently, argv[0] must be an absolute or relative path to the "
+ "executable.";
+ return ""; // Never executed. Needed so compiler does not complain.
+#else
+# error This BSD is not supported
+#endif
}
uint64_t GetMillisecondsMonotonic() {
@@ -103,10 +151,11 @@
}
void SetScheduling(bool batch_cpu_scheduling, int io_nice_level) {
- // Stubbed out so we can compile for FreeBSD.
+ // Stubbed out so we can compile.
}
blaze_util::Path GetProcessCWD(int pid) {
+#if defined(HAVE_PROCSTAT)
if (kill(pid, 0) < 0) {
return blaze_util::Path();
}
@@ -136,6 +185,9 @@
}
procstat_close(procstat);
return blaze_util::Path(cwd);
+#else
+ return blaze_util::Path("");
+#endif
}
bool IsSharedLibrary(const string &filename) {
@@ -143,7 +195,7 @@
}
string GetSystemJavabase() {
- // if JAVA_HOME is defined, then use it as default.
+ // If JAVA_HOME is defined, then use it as default.
string javahome = GetPathEnv("JAVA_HOME");
if (!javahome.empty()) {
@@ -155,7 +207,7 @@
<< "Ignoring JAVA_HOME, because it must point to a JDK, not a JRE.";
}
- return "/usr/local/openjdk8";
+ return DEFAULT_SYSTEM_JAVABASE;
}
int ConfigureDaemonProcess(posix_spawnattr_t *attrp,
diff --git a/src/main/cpp/blaze_util_darwin.cc b/src/main/cpp/blaze_util_darwin.cc
index 62f08c8..a484f00 100644
--- a/src/main/cpp/blaze_util_darwin.cc
+++ b/src/main/cpp/blaze_util_darwin.cc
@@ -124,7 +124,7 @@
}
}
-string GetSelfPath() {
+string GetSelfPath(const char* argv0) {
char pathbuf[PROC_PIDPATHINFO_MAXSIZE] = {};
int len = proc_pidpath(getpid(), pathbuf, sizeof(pathbuf));
if (len == 0) {
diff --git a/src/main/cpp/blaze_util_linux.cc b/src/main/cpp/blaze_util_linux.cc
index 76344fd..3cfea54 100644
--- a/src/main/cpp/blaze_util_linux.cc
+++ b/src/main/cpp/blaze_util_linux.cc
@@ -82,7 +82,7 @@
}
}
-string GetSelfPath() {
+string GetSelfPath(const char* argv0) {
// The file to which this symlink points could change contents or go missing
// concurrent with execution of the Bazel client, so we don't eagerly resolve
// it.
diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h
index 8545dfa..0056163 100644
--- a/src/main/cpp/blaze_util_platform.h
+++ b/src/main/cpp/blaze_util_platform.h
@@ -106,9 +106,9 @@
std::string GetProcessIdAsString();
-// Get an absolute path to the binary being executed that is guaranteed to be
+// Gets an absolute path to the binary being executed that is guaranteed to be
// readable.
-std::string GetSelfPath();
+std::string GetSelfPath(const char* argv0);
// Returns the directory Bazel can use to store output.
std::string GetOutputRoot();
@@ -129,7 +129,12 @@
// on Linux, so it should only be called when necessary.
void SetScheduling(bool batch_cpu_scheduling, int io_nice_level);
-// Returns the cwd for a process.
+// Returns the cwd of the specified process, or an empty string if the
+// directory is unknown.
+//
+// TODO(aldersondrive): Change the return type to
+// std::unique_ptr<blaze_util::Path>, so that we can return nullptr instead of
+// relying on callers to recognize the empty string as special.
blaze_util::Path GetProcessCWD(int pid);
bool IsSharedLibrary(const std::string& filename);
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc
index 401f9db..cd702db 100644
--- a/src/main/cpp/blaze_util_windows.cc
+++ b/src/main/cpp/blaze_util_windows.cc
@@ -383,7 +383,7 @@
return ToString(GetCurrentProcessId());
}
-string GetSelfPath() {
+string GetSelfPath(const char* argv0) {
WCHAR buffer[kWindowsPathBufferSize] = {0};
if (!GetModuleFileNameW(0, buffer, kWindowsPathBufferSize)) {
BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR)
diff --git a/src/main/native/BUILD b/src/main/native/BUILD
index 7813537..329e9c0 100644
--- a/src/main/native/BUILD
+++ b/src/main/native/BUILD
@@ -6,6 +6,7 @@
"//src/conditions:darwin": ["//tools/jdk:jni_md_header-darwin"],
"//src/conditions:darwin_x86_64": ["//tools/jdk:jni_md_header-darwin"],
"//src/conditions:freebsd": ["//tools/jdk:jni_md_header-freebsd"],
+ "//src/conditions:openbsd": ["//tools/jdk:jni_md_header-openbsd"],
"//src/conditions:windows": ["//tools/jdk:jni_md_header-windows"],
"//conditions:default": ["//tools/jdk:jni_md_header-linux"],
}),
@@ -33,7 +34,8 @@
"unix_jni_darwin.cc",
"fsevents.cc",
],
- "//src/conditions:freebsd": ["unix_jni_freebsd.cc"],
+ "//src/conditions:freebsd": ["unix_jni_bsd.cc"],
+ "//src/conditions:openbsd": ["unix_jni_bsd.cc"],
"//conditions:default": ["unix_jni_linux.cc"],
}),
)
diff --git a/src/main/native/unix_jni.cc b/src/main/native/unix_jni.cc
index cd3e753..7110c48 100644
--- a/src/main/native/unix_jni.cc
+++ b/src/main/native/unix_jni.cc
@@ -85,7 +85,9 @@
case ENAMETOOLONG: // File name too long
case ENODATA: // No data available
case EINVAL: // Invalid argument
+#if defined(EMULTIHOP)
case EMULTIHOP: // Multihop attempted
+#endif
case ENOLINK: // Link has been severed
case EIO: // I/O error
case EAGAIN: // Try again
diff --git a/src/main/native/unix_jni.h b/src/main/native/unix_jni.h
index 7a6c307..1127698 100644
--- a/src/main/native/unix_jni.h
+++ b/src/main/native/unix_jni.h
@@ -17,6 +17,7 @@
#ifndef BAZEL_SRC_MAIN_NATIVE_UNIX_JNI_H__
#define BAZEL_SRC_MAIN_NATIVE_UNIX_JNI_H__
+#include <errno.h>
#include <jni.h>
#include <sys/stat.h>
@@ -33,7 +34,7 @@
} \
} while (0)
-#if defined(__APPLE__) || defined(__FreeBSD__)
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
// stat64 is deprecated on OS X/BSD.
typedef struct stat portable_stat_struct;
#define portable_stat ::stat
@@ -44,8 +45,12 @@
#define portable_lstat ::lstat64
#endif
-#if defined(__FreeBSD__)
-#define ENODATA ENOATTR
+#if !defined(ENODATA)
+# if defined(ENOATTR)
+# define ENODATA ENOATTR
+# else
+# error Don't know how to handle missing ENODATA
+# endif
#endif
// Posts a JNI exception to the current thread with the specified
diff --git a/src/main/native/unix_jni_freebsd.cc b/src/main/native/unix_jni_bsd.cc
similarity index 86%
rename from src/main/native/unix_jni_freebsd.cc
rename to src/main/native/unix_jni_bsd.cc
index 8fd7ae2..05c744f 100644
--- a/src/main/native/unix_jni_freebsd.cc
+++ b/src/main/native/unix_jni_bsd.cc
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#if defined(__FreeBSD__)
+# define HAVE_EXTATTR
+# define HAVE_SYSCTLBYNAME
+#elif defined(__OpenBSD__)
+// No sys/extattr.h or sysctlbyname on this platform.
+#else
+# error This BSD is not supported
+#endif
+
#include "src/main/native/unix_jni.h"
#include <assert.h>
@@ -19,7 +28,9 @@
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/extattr.h>
+#if defined(HAVE_EXTATTR)
+# include <sys/extattr.h>
+#endif
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
@@ -74,22 +85,37 @@
ssize_t portable_getxattr(const char *path, const char *name, void *value,
size_t size, bool *attr_not_found) {
+#if (HAVE_EXTATTR)
ssize_t result =
extattr_get_file(path, EXTATTR_NAMESPACE_SYSTEM, name, value, size);
*attr_not_found = (errno == ENOATTR);
return result;
+#else
+ *attr_not_found = true;
+ return -1;
+#endif
}
ssize_t portable_lgetxattr(const char *path, const char *name, void *value,
size_t size, bool *attr_not_found) {
+#if (HAVE_EXTATTR)
ssize_t result =
extattr_get_link(path, EXTATTR_NAMESPACE_SYSTEM, name, value, size);
*attr_not_found = (errno == ENOATTR);
return result;
+#else
+ *attr_not_found = true;
+ return -1;
+#endif
}
int portable_sysctlbyname(const char *name_chars, long *mibp, size_t *sizep) {
+#if (HAVE_SYSCTLBYNAME)
return sysctlbyname(name_chars, mibp, sizep, NULL, 0);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
}
int portable_push_disable_sleep() {