diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4712,6 +4712,14 @@ def fno_sycl : Flag<["-"], "fno-sycl">, Flags<[NoXarchOption, CoreOption]>, Group, HelpText<"Disables SYCL kernels compilation for device">; +//===----------------------------------------------------------------------===// +// FLangOption + NoXarchOption +//===----------------------------------------------------------------------===// + +def flang_experimental_exec : Flag<["-"], "flang-experimental-exec">, + Flags<[FlangOption, FlangOnlyOption, NoXarchOption, HelpHidden]>, + HelpText<"Enable support for generating executables (experimental)">; + //===----------------------------------------------------------------------===// // FLangOption + CoreOption + NoXarchOption //===----------------------------------------------------------------------===// diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -382,6 +382,28 @@ Exec, CmdArgs, Inputs, Output)); } +static void addFortranRuntimeLibraryPath(const ToolChain &TC, + const ArgList &Args, + ArgStringList &CmdArgs) { + // Default to the /../lib directory. This works fine on the + // platforms that we have tested so far. We will probably have to re-fine + // this in the future. In particular: + // * on some platforms, we may need to use lib64 instead of lib + // * this logic should also work on other similar platforms too, so we + // should move it to one of Gnu's parent tool{chain} classes + SmallString<256> DefaultLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + llvm::sys::path::append(DefaultLibPath, "lib"); + CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath)); +} + +static void addFortranLinkerFlags(ArgStringList &CmdArgs) { + CmdArgs.push_back("-lFortran_main"); + CmdArgs.push_back("-lFortranRuntime"); + CmdArgs.push_back("-lFortranDecimal"); + CmdArgs.push_back("-lm"); +} + void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -586,6 +608,19 @@ // Silence warnings when linking C code with a C++ '-stdlib' argument. Args.ClaimAllArgs(options::OPT_stdlib_EQ); + // Additional linker set-up and flags for Fortran. This is required in order + // to generate executables. As Fortran runtime depends on the C runtime, + // these dependencies need to be listed before the C runtime below (i.e. + // AddRuntTimeLibs). + // + // NOTE: Generating executables by Flang is considered an "experimental" + // feature and hence this is guarded with a command line option. + // TODO: Make this work unconditionally once Flang is mature enough. + if (D.IsFlangMode() && Args.hasArg(options::OPT_flang_experimental_exec)) { + addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs); + addFortranLinkerFlags(CmdArgs); + } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (IsStatic || IsStaticPIE) diff --git a/flang/include/flang/Runtime/stop.h b/flang/include/flang/Runtime/stop.h --- a/flang/include/flang/Runtime/stop.h +++ b/flang/include/flang/Runtime/stop.h @@ -27,7 +27,7 @@ NORETURN void RTNAME(ProgramEndStatement)(NO_ARGUMENTS); // Extensions -NORETURN void RTNAME(Exit)(int status = EXIT_SUCCESS); +NORETURN void RTNAME(Exit)(int status DEFAULT_VALUE(EXIT_SUCCESS)); NORETURN void RTNAME(Abort)(NO_ARGUMENTS); // Crash with an error message when the program dynamically violates a Fortran diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt --- a/flang/runtime/CMakeLists.txt +++ b/flang/runtime/CMakeLists.txt @@ -30,6 +30,8 @@ # with different names include_directories(AFTER ${CMAKE_CURRENT_BINARY_DIR}) +add_subdirectory(FortranMain) + add_flang_library(FortranRuntime ISO_Fortran_binding.cpp allocatable.cpp diff --git a/flang/runtime/FortranMain/CMakeLists.txt b/flang/runtime/FortranMain/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/flang/runtime/FortranMain/CMakeLists.txt @@ -0,0 +1,3 @@ +llvm_add_library(Fortran_main STATIC + Fortran_main.c +) diff --git a/flang/runtime/FortranMain/Fortran_main.c b/flang/runtime/FortranMain/Fortran_main.c new file mode 100644 --- /dev/null +++ b/flang/runtime/FortranMain/Fortran_main.c @@ -0,0 +1,21 @@ +//===-- runtime/FortranMain/Fortran_main.c --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/Runtime/main.h" +#include "flang/Runtime/stop.h" + +/* main entry into PROGRAM */ +void _QQmain(); + +/* C main stub */ +int main(int argc, const char *argv[], const char *envp[]) { + RTNAME(ProgramStart)(argc, argv, envp); + _QQmain(); + RTNAME(ProgramEndStatement)(); + return 0; +} diff --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt --- a/flang/test/CMakeLists.txt +++ b/flang/test/CMakeLists.txt @@ -58,6 +58,9 @@ llvm-dis llvm-objdump split-file + FortranRuntime + Fortran_main + FortranDecimal ) if (FLANG_INCLUDE_TESTS) diff --git a/flang/test/Driver/driver-help-hidden.f90 b/flang/test/Driver/driver-help-hidden.f90 --- a/flang/test/Driver/driver-help-hidden.f90 +++ b/flang/test/Driver/driver-help-hidden.f90 @@ -38,6 +38,8 @@ ! CHECK-NEXT: -finput-charset= Specify the default character set for source files ! CHECK-NEXT: -fintrinsic-modules-path ! CHECK-NEXT: Specify where to find the compiled intrinsic modules +! CHECK-NEXT: -flang-experimental-exec +! CHECK-NEXT: Enable support for generating executables (experimental) ! CHECK-NEXT: -flarge-sizes Use INTEGER(KIND=8) for the result type in size-related intrinsics ! CHECK-NEXT: -flogical-abbreviations Enable logical abbreviations ! CHECK-NEXT: -fno-automatic Implies the SAVE attribute for non-automatic local objects in subprograms unless RECURSIVE diff --git a/flang/test/Driver/linker-flags.f90 b/flang/test/Driver/linker-flags.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Driver/linker-flags.f90 @@ -0,0 +1,31 @@ +! Verify that the Fortran runtime libraries are present in the linker +! invocation. These libraries are added on top of other standard runtime +! libraries that the Clang driver will include. + +! NOTE: The additional linker flags tested here are currently specified in +! clang/lib/Driver/Toolchains/Gnu.cpp. This makes the current implementation GNU +! (Linux) specific. The following line will make sure that this test is skipped +! on Windows. Ideally we should find a more robust way of testing this. +! REQUIRES: shell +! UNSUPPORTED: darwin, macos, system-windows + +!------------ +! RUN COMMAND +!------------ +! Use `--ld-path` so that the linker location (used in the LABEL below) is deterministic. +! RUN: %flang -### -flang-experimental-exec --ld-path=/usr/bin/ld %S/Inputs/hello.f90 2>&1 | FileCheck %s + +!---------------- +! EXPECTED OUTPUT +!---------------- +! Compiler invocation to generate the object file +! CHECK-LABEL: {{.*}} "-emit-obj" +! CHECK-SAME: "-o" "[[object_file:.*]]" {{.*}}Inputs/hello.f90 + +! Linker invocation to generate the executable +! CHECK-LABEL: "/usr/bin/ld" +! CHECK-SAME: "[[object_file]]" +! CHECK-SAME: -lFortran_main +! CHECK-SAME: -lFortranRuntime +! CHECK-SAME: -lFortranDecimal +! CHECK-SAME: -lm diff --git a/flang/tools/flang-driver/CMakeLists.txt b/flang/tools/flang-driver/CMakeLists.txt --- a/flang/tools/flang-driver/CMakeLists.txt +++ b/flang/tools/flang-driver/CMakeLists.txt @@ -13,6 +13,14 @@ add_flang_tool(flang-new driver.cpp fc1_main.cpp + + DEPENDS + # These libraries are used in the linker invocation generated by the driver + # (i.e. when constructing the linker job). Without them the driver would be + # unable to generate executables. + FortranRuntime + FortranDecimal + Fortran_main ) target_link_libraries(flang-new