Skip to content

Commit

Permalink
Merge pull request idris-lang#3162 from AdamHarries/compilerEnvs
Browse files Browse the repository at this point in the history
[fix] correctly pass environment vars to the RefC compiler
  • Loading branch information
andrevidela authored Dec 20, 2023
2 parents 3502f4a + ec44ff9 commit 58e5d15
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 16 deletions.
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@

#### RefC

* Adds support for `CFLAGS`, `CPPFLAGS`, and `LDFLAGS` to facilitate building on
systems with non-standard installation locations of libraries (e.g. GMP).
Versions of the flags with the `IDRIS2_` prefix can also be used and take
precedence.
* Adds support for `CFLAGS`, `CPPFLAGS`, `LDFLAGS` and `LDLIBS` to facilitate
building on systems with non-standard installation locations of libraries
(e.g. GMP). Versions of the flags with the `IDRIS2_` prefix can also be used
and take precedence.

#### Chez

Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Thanks to the following for their help and contributions to Idris 2:

Aaron Lebahn
Abdelhakim Qbaich
Adam Brouwers-Harries
Alain Zscheile
Aleksei Volkov
Alex Gryzlov
Expand Down
2 changes: 2 additions & 0 deletions docs/source/reference/envvars.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ Both
* ``IDRIS2_CFLAGS`` - RefC backend: C compiler flags.
* ``IDRIS2_CPPFLAGS`` - RefC backend: C preprocessor flags.
* ``IDRIS2_LDFLAGS`` - RefC backend: C linker flags.
* ``IDRIS2_LDLIBS`` - RefC backend: C linker library names or flags.
* ``CC`` - RefC backend: C compiler executable (IDRIS2_CC takes precedence).
* ``CFLAGS`` - RefC backend: C compiler flags (IDRIS2_CFLAGS takes precedence).
* ``CPPFLAGS`` - RefC backend: C preprocessor flags (IDRIS2_CPPFLAGS takes precedence).
* ``LDFLAGS`` - RefC backend: C linker flags (IDRIS2_LDFLAGS takes precedence).
* ``LDLIBS`` - RefC backend: C linker library names or flags.
* ``NODE`` - NodeJS backend: ``node`` executable.
* ``PATH`` - PATH variable is used to search for executables in certain
codegens.
Expand Down
39 changes: 27 additions & 12 deletions src/Compiler/RefC/CC.idr
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,52 @@ import Core.Options
import Core.Directory

import System
import Idris.Env

import Data.String

%default total

findCC : IO String
findCC
= do Nothing <- getEnv "IDRIS2_CC"
= do Nothing <- idrisGetEnv "IDRIS2_CC"
| Just cc => pure cc
Nothing <- getEnv "CC"
Nothing <- idrisGetEnv "CC"
| Just cc => pure cc
pure "cc"

findCFLAGS : IO String
findCFLAGS
= do Nothing <- getEnv "IDRIS2_CFLAGS"
= do Nothing <- idrisGetEnv "IDRIS2_CFLAGS"
| Just cflags => pure cflags
Nothing <- getEnv "CFLAGS"
Nothing <- idrisGetEnv "CFLAGS"
| Just cflags => pure cflags
pure ""

findCPPFLAGS : IO String
findCPPFLAGS
= do Nothing <- getEnv "IDRIS2_CPPFLAGS"
= do Nothing <- idrisGetEnv "IDRIS2_CPPFLAGS"
| Just cppflags => pure cppflags
Nothing <- getEnv "CPPFLAGS"
Nothing <- idrisGetEnv "CPPFLAGS"
| Just cppflags => pure cppflags
pure ""

findLDFLAGS : IO String
findLDFLAGS
= do Nothing <- getEnv "IDRIS2_LDFLAGS"
= do Nothing <- idrisGetEnv "IDRIS2_LDFLAGS"
| Just ldflags => pure ldflags
Nothing <- getEnv "LDFLAGS"
Nothing <- idrisGetEnv "LDFLAGS"
| Just ldflags => pure ldflags
pure ""

findLDLIBS : IO String
findLDLIBS
= do Nothing <- idrisGetEnv "IDRIS2_LDLIBS"
| Just ldlibs => pure ldlibs
Nothing <- idrisGetEnv "LDLIBS"
| Just ldlibs => pure ldlibs
pure ""

clibdirs : List String -> List String
clibdirs ds = map (\d => "-L" ++ d) ds

Expand All @@ -63,11 +74,13 @@ compileCObjectFile {asLibrary} sourceFile objectFile =

let libraryFlag = if asLibrary then ["-fpic"] else []

let runccobj = escapeCmd $
let runccobj = (escapeCmd $
[cc, "-Werror", "-c"] ++ libraryFlag ++ [sourceFile,
"-o", objectFile,
"-I" ++ refcDir,
"-I" ++ cDir]
"-I" ++ cDir])
++ " " ++ cppFlags ++ " " ++ cFlags


log "compiler.refc.cc" 10 runccobj
0 <- coreLift $ system runccobj
Expand All @@ -85,21 +98,23 @@ compileCFile {asShared} objectFile outFile =
do cc <- coreLift findCC
cFlags <- coreLift findCFLAGS
ldFlags <- coreLift findLDFLAGS
ldLibs <- coreLift findLDLIBS

dirs <- getDirs
refcDir <- findDataFile "refc"
supportFile <- findLibraryFile "libidris2_support.a"

let sharedFlag = if asShared then ["-shared"] else []

let runcc = escapeCmd $
let runcc = (escapeCmd $
[cc, "-Werror"] ++ sharedFlag ++ [objectFile,
"-o", outFile,
supportFile,
"-lidris2_refc",
"-L" ++ refcDir
] ++ clibdirs (lib_dirs dirs) ++ [
"-lgmp", "-lm"]
"-lgmp", "-lm"])
++ " " ++ (unwords [cFlags, ldFlags, ldLibs])

log "compiler.refc.cc" 10 runcc
0 <- coreLift $ system runcc
Expand Down
2 changes: 2 additions & 0 deletions src/Idris/Env.idr
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ envs = [
MkEnvDesc "IDRIS2_CFLAGS" "RefC backend: C compiler flags.",
MkEnvDesc "IDRIS2_CPPFLAGS" "RefC backend: C preprocessor flags.",
MkEnvDesc "IDRIS2_LDFLAGS" "RefC backend: C linker flags.",
MkEnvDesc "IDRIS2_LDLIBS" "RefC backend: C linker library names or flags.",
MkEnvDesc "CC" "RefC backend: C compiler executable (IDRIS2_CC takes precedence).",
MkEnvDesc "CFLAGS" "RefC backend: C compiler flags (IDRIS2_CFLAGS takes precedence).",
MkEnvDesc "CPPFLAGS" "RefC backend: C preprocessor flags (IDRIS2_CPPFLAGS takes precedence).",
MkEnvDesc "LDFLAGS" "RefC backend: C linker flags (IDRIS2_LDFLAGS takes precedence).",
MkEnvDesc "LDLIBS" "RefC backend: C linker library names or flags (IDRIS2_LDLIBS takes precedence).",
MkEnvDesc "NODE" "NodeJS backend: NodeJS executable.",
MkEnvDesc "PATH" "PATH variable is used to search for executables in certain codegens.",
MkEnvDesc "NO_COLOR" "Instruct Idris not to print color to stdout. Passing the --color/--colour option will supersede this env var."]
Expand Down
15 changes: 15 additions & 0 deletions tests/refc/ccompilerArgs/Main.idr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import System.FFI

libexternal : String -> String
libexternal fn = "C:" ++ fn ++ ",libexternalc,externalc.h"

%foreign (libexternal "add")
add : Int -> Int -> Int

%foreign (libexternal "fastfibsum")
fastfibsum : Int -> Int

main : IO ()
main = do
printLn $ show (add 50 23)
printLn $ show ([fastfibsum x | x <- [0..10]])
2 changes: 2 additions & 0 deletions tests/refc/ccompilerArgs/expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"73"
"[0, 1, 2, 4, 7, 12, 20, 33, 54, 88, 143]"
10 changes: 10 additions & 0 deletions tests/refc/ccompilerArgs/library/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
all: libexternalc.so

externalc.o: externalc.c externalc.h
$(CC) -c -fPIC $< -o $@

libexternalc.so: externalc.o
$(CC) $< -shared -o $@

clean:
rm -f externalc.o externalc.so
17 changes: 17 additions & 0 deletions tests/refc/ccompilerArgs/library/externalc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "externalc.h"

int add(int x, int y) { return x + y; }

int fastfibsum(int x) {
int acc = 0;
int p = 0;
int c = 1;
int tmp;
for (; 0 <= --x;) {
acc += c;
tmp = c;
c = c + p;
p = tmp;
}
return acc;
}
3 changes: 3 additions & 0 deletions tests/refc/ccompilerArgs/library/externalc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
int add(int x, int y);

int fastfibsum(int x);
31 changes: 31 additions & 0 deletions tests/refc/ccompilerArgs/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
. ../../testutils.sh

# This test checks to make sure that Idris2's command line handling for the RefC backend is correct.
# It checks that:
# 1) Idris2 correctly finds `CFLAGS` and `LDFLAGS` in the environment,
# 2) The values in `CFLAGS` and `LDFLAGS` are separated correctly to be passed to the compiler
#
# (1) is achieved by compiling a c library (`externalc`) in a separate folder, and then explicitly
# pointing the compiler to the header files (with `-I./library/`) and shared library (with `-L./library`)
# and requesting that libexternalc.{so,dylib,dll} is linked (with `-lexternalc`). We additionally point the
# dynamic library loader to the correct location with `DYLD_LIBRARY_PATH`.
#
# (2) is achieved by passing multiple options, separated by spaces, in each of `CFLAGS` and `LDFLAGS`.
# These options are `-O3` for the c flags, and `-Wl,-pie` for the linker flags. They do not change the
# semantics of the resulting code (`-O3` simply optimises it more, and `-Wl,-S` removes debugging information
# from the final executable), but do check that we correctly split up the environment variables when we
# pass them to the C compiler.

cd ./library/
make > /dev/null
cd ..

export CFLAGS="-I./library/ -O3"
export LDFLAGS="-L./library/ -Wl,-S"
export LDLIBS="-lexternalc"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:./library/"
export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:./library/"

idris2 --cg refc -o cffi Main.idr > /dev/null

./build/exec/cffi

0 comments on commit 58e5d15

Please sign in to comment.