Fortran rules?

413 views
Skip to first unread message

Austin Schuh

unread,
Nov 9, 2015, 2:37:56 AM11/9/15
to bazel-discuss
I'm looking to build Slycot from scratch.  To do that, it looks like I need to call f2py to generate a .c file.  That will then be used in a shared library that python imports along with the original fortran files.

Has anyone built fortran code with bazel before and linked it into a c/c++ shared library?

Thanks!
  Austin

Han-Wen Nienhuys

unread,
Nov 9, 2015, 6:43:54 AM11/9/15
to Austin Schuh, bazel-discuss
Not directly, but I've seen the Google fortran rules, and IIRC, they
just run $(CC) on the .f files in a genrule.
> --
> You received this message because you are subscribed to the Google Groups
> "bazel-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to bazel-discus...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/bazel-discuss/CABsbf%3DEq50ED1XoFxazRoDtkZsN7B3GMBtCr5jaBQWrbLET%3DSg%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.



--
Han-Wen Nienhuys
Google Munich
han...@google.com

Austin Schuh

unread,
Nov 12, 2015, 4:20:43 AM11/12/15
to Han-Wen Nienhuys, bazel-discuss
Success!  Thanks!

(I cut a couple corners that I'd like to clean up, but it successfully builds libraries that I can build into a shared library).

I'm working on building https://github.com/avventi/Slycot so I can use it in a python script in a genrule to do codegen.  I'm doing controller pole placement and kalman filter design with it.  The last remaining issue is that Slycot expects the shared library to be in @slycot_repo//slycot:_wrapper.so, and I can only generate a BUILD file which puts it in @slycot_repo//:_wrapper.so since I'm using new_git_repository.

I've tried a couple ways to get around that.  I've tried generating a symlink in @slycot_repo//slycot/ pointing to ../_wrapper.so.  When I do that, I get a lovely 'libexternal_Sslycot_Urepo_Slibslycot_Uc.so: cannot open shared object file: No such file or directory' error, and using strace, I see that it is searching ../../_solib_k8/, which is missing 1 ../.  To me, that means that the library needs to have that exact path, so it can't be moved (or linked to).

cc_binary(
  name = '_wrapper.so',
  deps = [
    ':fortran_files',
    ':slycot_c',
  ],
  linkopts = ['-shared', '-lblas', '-llapack'],
  linkstatic=0,
)

If I try linkstatic=1, it tries to pull the .o files to link into the .so from the .a generated by the fortran_library, which doesn't have .o's.  Even if it had .o's, would be compiled without -fPIC, which doesn't work.  Ideally, if this worked, the _wrapper.so library could be moved since it would be pretty self-sufficient.

It looks like my best option might be to fork the repository and add the BUILD files in that way.  That means that I need to keep rebasing if upstream adds fixes, and maintain a separate repository.  I don't really like that solution.

Any suggestions?
Austin


For reference, Fortran library rules.  I'm not sure my approach is general enough to submit upstream.  If there is interest and I can get a bit of guidance on how to improve them, I'd be happy to submit them.

def _single_fortran_object_impl(ctx):
  toolchain_cflags = (ctx.fragments.cpp.compiler_options([]) +
      ctx.fragments.cpp.c_options +
      ctx.fragments.cpp.unfiltered_compiler_options([]) + ['-fPIC'])

  cmd = [ctx.fragments.cpp.compiler_executable] + toolchain_cflags + ['-c', ctx.file.src.path, '-o', ctx.outputs.pic_o.path]
  filtered_cmd = []
  exclude_flags = ['-fcolor-diagnostics',
                   '-Wswitch-enum',
                   '-Wpointer-arith',
                   '-Wcast-qual',
                   '-Wwrite-strings',
                   '-Wsign-compare',
                   '-Wformat=2',
                   '-Werror',
                   '-Wno-builtin-macro-redefined']

  for flag in cmd:
    if flag not in exclude_flags:
      filtered_cmd.append(flag)

  ctx.action(
    inputs = [ctx.file.src],
    outputs = [ctx.outputs.pic_o],
    mnemonic = "Fortran",
    command = ' '.join(filtered_cmd),
    progress_message = 'Building %s' % ctx.outputs.pic_o.short_path,
  )

def _define_fortran_output(attrs):
  if not attrs.src.name.endswith('.f'):
    fail('Fortran files must end in \'.f\'', 'src')

  fortran_file_base = attrs.src.name[:-2]
  return {
    'pic_o': fortran_file_base + '.pic.o',
  }


_single_fortran_object = rule(
  implementation = _single_fortran_object_impl,
  attrs = {
    'src': attr.label(single_file=True, allow_files=FileType(['.f'])),
    'cc_libs': attr.label_list(providers=['cc']),
  },
  outputs = _define_fortran_output,
  fragments = [
    'cpp',
  ],
)

def fortran_library(name, srcs, deps = [], visibility = None):
  pic_o_files = []
  for src in srcs:
    pic_o_file = src[:-2] + '.pic.o'
    _single_fortran_object(name=name + '_' + pic_o_file,
                           src=src,
                           visibility=['//visibility:private'])
    pic_o_files.append(pic_o_file)

  native.cc_library(
    name = name,
    deps = deps,
    srcs = pic_o_files,
    linkopts = [
      '-lgfortran', 
    ],
    visibility = visibility,
  )
Reply all
Reply to author
Forward
0 new messages