Add flang out of tree buildbot

This builder has 2 stages: one for building llvm and mlir, and one for
building flang itself in a different build directory. In order to do an
out of tree build of flang, we need to run cmake with the path to the
flang subproject as source directory.

Differential Revision: https://reviews.llvm.org/D87085
diff --git a/buildbot/osuosl/master/config/builders.py b/buildbot/osuosl/master/config/builders.py
index 8db2373..0eca50d 100644
--- a/buildbot/osuosl/master/config/builders.py
+++ b/buildbot/osuosl/master/config/builders.py
@@ -1,6 +1,7 @@
 from buildbot.process.properties import WithProperties
 
 from zorg.buildbot.builders import ClangBuilder
+from zorg.buildbot.builders import FlangBuilder
 from zorg.buildbot.builders import PollyBuilder
 from zorg.buildbot.builders import LLDBBuilder
 from zorg.buildbot.builders import SanitizerBuilder
@@ -1553,6 +1554,24 @@
          ),
          'category' : 'flang'},
 
+        {'name': "flang-aarch64-ubuntu-out-of-tree",
+         'slavenames':["linaro-aarch64-flang-oot"],
+         'builddir':"flang-aarch64-out-of-tree",
+         'factory': FlangBuilder.getFlangOutOfTreeBuildFactory(
+             llvm_extra_configure_args=[
+                 "-DLLVM_TARGETS_TO_BUILD=AArch64",
+                 "-DCMAKE_CXX_STANDARD=17",
+                 "-DLLVM_ENABLE_WERROR=OFF",
+                 "-DLLVM_ENABLE_ASSERTIONS=ON",
+                 "-DCMAKE_BUILD_TYPE=Release",
+             ],
+             flang_extra_configure_args=[
+                 "-DFLANG_ENABLE_WERROR=ON",
+                 "-DCMAKE_BUILD_TYPE=Release",
+            ],
+        ),
+        'category' : 'flang'},
+
         {'name': "flang-x86_64-linux",
          'slavenames':["nersc-flang"],
          'builddir':"flang-x86_64-linux",
diff --git a/buildbot/osuosl/master/config/slaves.py b/buildbot/osuosl/master/config/slaves.py
index d76097b..87a2b35 100644
--- a/buildbot/osuosl/master/config/slaves.py
+++ b/buildbot/osuosl/master/config/slaves.py
@@ -44,6 +44,7 @@
         create_slave("linaro-aarch64-full", properties={'jobs' : 32}, max_builds=1),
         create_slave("linaro-aarch64-global-isel", properties={'jobs' : 32}, max_builds=1),
         create_slave("linaro-aarch64-lld", properties={'jobs' : 32}, max_builds=1),
+        create_slave("linaro-aarch64-flang-oot", properties={'jobs' : 32}, max_builds=1),
         # Libcxx testsuite has tests with timing assumptions.  Run single-threaded to make
         # sure we have plenty CPU cycle to satisfy timing assumptions.
         create_slave("linaro-aarch64-libcxx", properties={'jobs' : 1}, max_builds=1),
diff --git a/zorg/buildbot/builders/FlangBuilder.py b/zorg/buildbot/builders/FlangBuilder.py
new file mode 100644
index 0000000..8f4e772
--- /dev/null
+++ b/zorg/buildbot/builders/FlangBuilder.py
@@ -0,0 +1,72 @@
+from zorg.buildbot.commands.CmakeCommand import CmakeCommand
+
+from zorg.buildbot.process.factory import LLVMBuildFactory
+
+from zorg.buildbot.builders.UnifiedTreeBuilder import addNinjaSteps, getCmakeWithNinjaBuildFactory
+
+def getFlangOutOfTreeBuildFactory(
+           checks = None,
+           clean = False,
+           llvm_extra_configure_args = None,
+           flang_extra_configure_args = None,
+           env = None,
+           **kwargs):
+
+    f = getCmakeWithNinjaBuildFactory(
+            depends_on_projects=['llvm','mlir'],
+            obj_dir="build_llvm",
+            checks=[],
+            clean=clean,
+            extra_configure_args=llvm_extra_configure_args,
+            env=env,
+            **kwargs)
+
+    if checks is None:
+        checks = ['check-all']
+
+    # Make a local copy of the flang configure args, as we are going to modify that.
+    if flang_extra_configure_args:
+        flang_cmake_args = flang_extra_configure_args[:]
+    else:
+        flang_cmake_args = list()
+
+    # Some options are required for this build no matter what.
+    CmakeCommand.applyRequiredOptions(flang_cmake_args, [
+        ('-G', 'Ninja'),
+        ])
+
+    flang_obj_dir = "build_flang"
+    flang_src_dir = "%s/flang" % f.monorepo_dir
+
+    # Add LLVM_DIR and MLIR_DIR to the CMake invocation.
+    llvm_dir = "%s/lib/cmake/llvm" % f.obj_dir
+    mlir_dir = "%s/lib/cmake/mlir" % f.obj_dir
+    CmakeCommand.applyRequiredOptions(flang_cmake_args, [
+        # We actually need the paths to be relative to the source directory,
+        # otherwise find_package can't locate the config files.
+        ('-DLLVM_DIR:PATH=',
+            LLVMBuildFactory.pathRelativeTo(llvm_dir, flang_src_dir)),
+        ('-DMLIR_DIR:PATH=',
+            LLVMBuildFactory.pathRelativeTo(mlir_dir, flang_src_dir)),
+        ])
+
+    # We can't use addCmakeSteps as that would use the path in f.llvm_srcdir.
+    f.addStep(CmakeCommand(name="cmake-configure-flang",
+                           haltOnFailure=True,
+                           description=["CMake", "configure", "flang"],
+                           options=flang_cmake_args,
+                           path=LLVMBuildFactory.pathRelativeTo(flang_src_dir,
+                                                                flang_obj_dir),
+                           env=env,
+                           workdir=flang_obj_dir,
+                           **kwargs))
+
+    addNinjaSteps(
+       f,
+       obj_dir=flang_obj_dir,
+       checks=checks,
+       env=env,
+       stage_name="flang",
+       **kwargs)
+
+    return f