Skip to content

Commit 97a32d3

Browse files
banach-spaceschweitzpgiklauslerjeanPerier
committed
[flang][driver] Add support for generating executables
This patch adds 2 missing items required for `flang-new` to be able to generate executables: 1. The Fortran_main runtime library, which implements the main entry point into Fortran's `PROGRAM` in Flang, 2. Extra linker flags to include Fortran runtime libraries (e.g. Fortran_main). Fortran_main is the bridge between object files generated by Flang and the C runtime that takes care of program set-up at system-level. For every Fortran `PROGRAM`, Flang generates the `_QQmain` function. Fortran_main implements the C `main` function that simply calls `_QQmain`. Additionally, "<driver-path>/../lib" directory is added to the list of search directories for libraries. This is where the required runtime libraries are currently located. Note that this the case for the build directory. We haven't considered installation directories/targets yet. With this change, you can generate an executable that will print `hello, world!` as follows: ```bash $ cat hello.f95 PROGRAM HELLO write(*, *) "hello, world!" END PROGRAM HELLO $ flang-new -flang-experimental-exec hello.f95 ./a.out hello, world! ``` NOTE 1: Fortran_main has to be a static library at all times. It invokes `_QQmain`, which is the main entry point generated by Flang for the given input file (you can check this with `flang-new -S hello.f95 -o - | grep "Qmain"`). This means that Fortran_main has an unresolved dependency at build time. The linker will allow this for a static library. However, if Fortran_main was a shared object, then the linker will produce an error: `undefined symbol: `_QQmain`. NOTE 2: When Fortran runtime libraries are generated as shared libraries (excluding Fortran_main, which is always static), you will need to tell the dynamic linker (by e.g. tweaking LD_LIBRARY_PATH) where to look for them when invoking the executables. For example: ```bash LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<flang-build-dir>/lib/ ./a.out ``` NOTE 3: This feature is considered experimental and currently guarded with a flag: `-flang-experimental-exec`. Differential Revision: https://reviews.llvm.org/D122008 [1] https://github.com/flang-compiler/f18-llvm-project CREDITS: Fortran_main was originally written by Eric Schweitz, Jean Perier, Peter Klausler and Steve Scalpone in the fir-dev` branch in [1]. Co-authored-by: Eric Schweitz <[email protected]> Co-authored-by: Peter Klausler <[email protected]> Co-authored-by: Jean Perier <[email protected]> Co-authored-by: Steve Scalpone <[email protected]
1 parent 2fee8dd commit 97a32d3

File tree

10 files changed

+114
-1
lines changed

10 files changed

+114
-1
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4712,6 +4712,14 @@ def fsycl : Flag<["-"], "fsycl">, Flags<[NoXarchOption, CoreOption]>,
47124712
def fno_sycl : Flag<["-"], "fno-sycl">, Flags<[NoXarchOption, CoreOption]>,
47134713
Group<sycl_Group>, HelpText<"Disables SYCL kernels compilation for device">;
47144714

4715+
//===----------------------------------------------------------------------===//
4716+
// FLangOption + NoXarchOption
4717+
//===----------------------------------------------------------------------===//
4718+
4719+
def flang_experimental_exec : Flag<["-"], "flang-experimental-exec">,
4720+
Flags<[FlangOption, FlangOnlyOption, NoXarchOption, HelpHidden]>,
4721+
HelpText<"Enable support for generating executables (experimental)">;
4722+
47154723
//===----------------------------------------------------------------------===//
47164724
// FLangOption + CoreOption + NoXarchOption
47174725
//===----------------------------------------------------------------------===//

clang/lib/Driver/ToolChains/Gnu.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,28 @@ void tools::gnutools::StaticLibTool::ConstructJob(
382382
Exec, CmdArgs, Inputs, Output));
383383
}
384384

385+
static void addFortranRuntimeLibraryPath(const ToolChain &TC,
386+
const ArgList &Args,
387+
ArgStringList &CmdArgs) {
388+
// Default to the <driver-path>/../lib directory. This works fine on the
389+
// platforms that we have tested so far. We will probably have to re-fine
390+
// this in the future. In particular:
391+
// * on some platforms, we may need to use lib64 instead of lib
392+
// * this logic should also work on other similar platforms too, so we
393+
// should move it to one of Gnu's parent tool{chain} classes
394+
SmallString<256> DefaultLibPath =
395+
llvm::sys::path::parent_path(TC.getDriver().Dir);
396+
llvm::sys::path::append(DefaultLibPath, "lib");
397+
CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
398+
}
399+
400+
static void addFortranLinkerFlags(ArgStringList &CmdArgs) {
401+
CmdArgs.push_back("-lFortran_main");
402+
CmdArgs.push_back("-lFortranRuntime");
403+
CmdArgs.push_back("-lFortranDecimal");
404+
CmdArgs.push_back("-lm");
405+
}
406+
385407
void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
386408
const InputInfo &Output,
387409
const InputInfoList &Inputs,
@@ -586,6 +608,19 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
586608
// Silence warnings when linking C code with a C++ '-stdlib' argument.
587609
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
588610

611+
// Additional linker set-up and flags for Fortran. This is required in order
612+
// to generate executables. As Fortran runtime depends on the C runtime,
613+
// these dependencies need to be listed before the C runtime below (i.e.
614+
// AddRuntTimeLibs).
615+
//
616+
// NOTE: Generating executables by Flang is considered an "experimental"
617+
// feature and hence this is guarded with a command line option.
618+
// TODO: Make this work unconditionally once Flang is mature enough.
619+
if (D.IsFlangMode() && Args.hasArg(options::OPT_flang_experimental_exec)) {
620+
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
621+
addFortranLinkerFlags(CmdArgs);
622+
}
623+
589624
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) {
590625
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
591626
if (IsStatic || IsStaticPIE)

flang/include/flang/Runtime/stop.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ NORETURN void RTNAME(FailImageStatement)(NO_ARGUMENTS);
2727
NORETURN void RTNAME(ProgramEndStatement)(NO_ARGUMENTS);
2828

2929
// Extensions
30-
NORETURN void RTNAME(Exit)(int status = EXIT_SUCCESS);
30+
NORETURN void RTNAME(Exit)(int status DEFAULT_VALUE(EXIT_SUCCESS));
3131
NORETURN void RTNAME(Abort)(NO_ARGUMENTS);
3232

3333
// Crash with an error message when the program dynamically violates a Fortran

flang/runtime/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ configure_file(config.h.cmake config.h)
3030
# with different names
3131
include_directories(AFTER ${CMAKE_CURRENT_BINARY_DIR})
3232

33+
add_subdirectory(FortranMain)
34+
3335
add_flang_library(FortranRuntime
3436
ISO_Fortran_binding.cpp
3537
allocatable.cpp
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
llvm_add_library(Fortran_main STATIC
2+
Fortran_main.c
3+
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- runtime/FortranMain/Fortran_main.c --------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "flang/Runtime/main.h"
10+
#include "flang/Runtime/stop.h"
11+
12+
/* main entry into PROGRAM */
13+
void _QQmain();
14+
15+
/* C main stub */
16+
int main(int argc, const char *argv[], const char *envp[]) {
17+
RTNAME(ProgramStart)(argc, argv, envp);
18+
_QQmain();
19+
RTNAME(ProgramEndStatement)();
20+
return 0;
21+
}

flang/test/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ set(FLANG_TEST_DEPENDS
5858
llvm-dis
5959
llvm-objdump
6060
split-file
61+
FortranRuntime
62+
Fortran_main
63+
FortranDecimal
6164
)
6265

6366
if (FLANG_INCLUDE_TESTS)

flang/test/Driver/driver-help-hidden.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
! CHECK-NEXT: -finput-charset=<value> Specify the default character set for source files
3939
! CHECK-NEXT: -fintrinsic-modules-path <dir>
4040
! CHECK-NEXT: Specify where to find the compiled intrinsic modules
41+
! CHECK-NEXT: -flang-experimental-exec
42+
! CHECK-NEXT: Enable support for generating executables (experimental)
4143
! CHECK-NEXT: -flarge-sizes Use INTEGER(KIND=8) for the result type in size-related intrinsics
4244
! CHECK-NEXT: -flogical-abbreviations Enable logical abbreviations
4345
! CHECK-NEXT: -fno-automatic Implies the SAVE attribute for non-automatic local objects in subprograms unless RECURSIVE

flang/test/Driver/linker-flags.f90

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
! Verify that the Fortran runtime libraries are present in the linker
2+
! invocation. These libraries are added on top of other standard runtime
3+
! libraries that the Clang driver will include.
4+
5+
! NOTE: The additional linker flags tested here are currently specified in
6+
! clang/lib/Driver/Toolchains/Gnu.cpp. This makes the current implementation GNU
7+
! (Linux) specific. The following line will make sure that this test is skipped
8+
! on Windows. Ideally we should find a more robust way of testing this.
9+
! REQUIRES: shell
10+
! UNSUPPORTED: darwin, macos, system-windows
11+
12+
!------------
13+
! RUN COMMAND
14+
!------------
15+
! Use `--ld-path` so that the linker location (used in the LABEL below) is deterministic.
16+
! RUN: %flang -### -flang-experimental-exec --ld-path=/usr/bin/ld %S/Inputs/hello.f90 2>&1 | FileCheck %s
17+
18+
!----------------
19+
! EXPECTED OUTPUT
20+
!----------------
21+
! Compiler invocation to generate the object file
22+
! CHECK-LABEL: {{.*}} "-emit-obj"
23+
! CHECK-SAME: "-o" "[[object_file:.*]]" {{.*}}Inputs/hello.f90
24+
25+
! Linker invocation to generate the executable
26+
! CHECK-LABEL: "/usr/bin/ld"
27+
! CHECK-SAME: "[[object_file]]"
28+
! CHECK-SAME: -lFortran_main
29+
! CHECK-SAME: -lFortranRuntime
30+
! CHECK-SAME: -lFortranDecimal
31+
! CHECK-SAME: -lm

flang/tools/flang-driver/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ set( LLVM_LINK_COMPONENTS
1313
add_flang_tool(flang-new
1414
driver.cpp
1515
fc1_main.cpp
16+
17+
DEPENDS
18+
# These libraries are used in the linker invocation generated by the driver
19+
# (i.e. when constructing the linker job). Without them the driver would be
20+
# unable to generate executables.
21+
FortranRuntime
22+
FortranDecimal
23+
Fortran_main
1624
)
1725

1826
target_link_libraries(flang-new

0 commit comments

Comments
 (0)