Zulip Chat Archive

Stream: lean4

Topic: Configuring Lakefile for multiple c files over the FFI


z battleman (Jun 13 2022 at 22:45):

Hi! I'm wondering if it's possible to configure a lakefile such that different lean files look to different c files when externing their functions (Apologies if my vernacular isn't right). It would be nice to have seperate files Foo.c and Bar.c which correspond to different lean files Foo.lean and Bar.lean`. Looking on Github, it seems most projects use one c file, so I'm wondering if it's possible to do such a thing. Thank you so much!

z battleman (Jun 14 2022 at 02:12):

In case anyone comes across this in the future, while I didn't manage to figure out how to do exactly what I described, what you can do is #include your other c files in a main c file which is referenced by your lakefile. Then, the only change to your lakefile is adding adding the new lean files to the libRoots in the declaration of the package

Mac (Jun 14 2022 at 03:02):

The target used in an extern_lib declaration is generally a static library (i.e., a staticLibTarget). You can pass as many different .o file targets as want to such a library and they will all be available to Lean files. To demonstration, here is an adaption of Lake's ffi example with multiple .c file inputs (i.e., a.c, b.c, c.c from the directory c):

def pkgDir := __dir__
def cSrcDir := pkgDir / "c"
def cBuildDir := pkgDir / _package.buildDir / "c"

def oTarget (fileName : String) : FileTarget :=
  let oFile := cBuildDir / s!"{fileName}.o"
  let srcTarget := inputFileTarget <| cSrcDir / s!"{fileName}.c"
  fileTargetWithDep oFile srcTarget fun srcFile => do
    compileO oFile srcFile #["-I", ( getLeanIncludeDir).toString] "cc"

extern_lib cLib :=
  let libFile := cBuildDir / "libffi.a"
  staticLibTarget libFile #[oTarget "a.c", oTarget "b.c", oTarget "c.c"]

z battleman (Jun 14 2022 at 03:50):

oh thank you so much!

Xubai Wang (Jun 16 2022 at 16:32):

I find it very difficult to express platform specific extern_lib when I'm updating socket package to new lakefile format: moreLibTargets := if Platform.isWindows then #[cLibTarget, inputFileTarget "C:\\Windows\\System32\\ws2_32.dll"] else #[cLibTarget]
Shall we now have conditional elaboration as Lean's builtin feature? For example with section-like format:

section if Platform.isWindows  -- only elaborate when if condition satisfies
extern_lib ws2 :=
  inputFileTarget "C:\\Windows\\System32\\ws2_32.dll"
end

Mac (Jun 16 2022 at 17:40):

Oof, yeah that is use case I forgot about. As a stop gap solution this should work:

import Lean.Elab.Command
import Lake.Util.EvalTerm
open Lake Lean Elab Command

elab "meta " "if " x:term " then " cmd:command : command => do
  if ( runTermElabM none <| fun _ => evalTerm Bool x) then elabCommand cmd

meta if System.Platform.isWindows then
extern_lib ws2 := inputFileTarget "C:\\Windows\\System32\\ws2_32.dll"

However, I will add a more long term solution later. My idea is to add a when block to specify the condition under which the extern_lib should be use. For example:

extern_lib ws2 :=
  inputFileTarget "C:\\Windows\\System32\\ws2_32.dll"
when
  System.Platform.isWindows

I lean towards this approach as it allows the target to still exist on other platforms (e.g., for potential cross-compilation) but just not be used by default.

I may still add meta utilities like the one above to the DSL, though.

Xubai Wang (Jun 16 2022 at 17:52):

Great!


Last updated: Dec 20 2023 at 11:08 UTC