Search code examples
pythonccmakepkg-config

Fuse API and CMake Build


I've recently re-opened a project I worked on a couple of years ago. I wrote a small python script to build the project. I would like to port that to CMake instead.

The problem I'm having is that the script uses pkg-config on linux to find the fuse headers and libraries. I'm having trouble porting this to CMake.

Here's the current python script

import subprocess, sys, os, shutil

def call( command ):

  c = subprocess.Popen( command.split(), stdout=subprocess.PIPE )
  c.wait()
  return c.stdout.read()

class GCC:

  args = None

  def __init__( self, initial_args ):

    self.args = initial_args

  def addPKG( self, package ):

    self.args.extend( package )

  def addFile( self, name ):

    self.args.append( name )

  def compile( self, out_name ):

    self.args.extend(["-o", out_name])
    print " ".join( self.args )
    gcc = subprocess.Popen( self.args )
    return gcc.wait() == 0


if __name__ == '__main__':

  cflags = call("pkg-config fuse --libs --cflags").split()

  print cflags

  gcc = GCC(["gcc","-g","-Wall","-pg"])
  gcc.addFile("argsparse.c")
  gcc.addFile("hidden.c")
  #gcc.addFile("fs.c")
  gcc.addFile("initialization.c")
  gcc.addFile("resolve.c")
  gcc.addFile("utilities.c")
  gcc.addFile("winhomefs0.4.c")
  gcc.addPKG(cflags)
  gcc.addFile("-lulockmgr")

  if gcc.compile("winhomefs") and 'install' in sys.argv:
    if os.getuid() == 0:
      shutil.copy("winhomefs", "/usr/local/bin/winhomefs")

Here's my current CMakeLists.txt file.

cmake_minimum_required (VERSION 2.8.11)
project (HomeFS)

set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
    "${CMAKE_SOURCE_DIR}/CMakeModules/")

find_package(FUSE REQUIRED)

add_library(argsparse argsparse.c)
add_library(hidden hidden.c)
add_library(initialization initialization.c)
add_library(resolve resolve.c)
add_library(utilities utilities.c)

add_executable(homefs winhomefs0.4.c)

The issue I'm having is with the find fuse part. I've tried several different permutations of it including the following...

https://github.com/tarruda/encfs/blob/master/CMakeModules/FindFUSE.cmake https://github.com/Pronghorn/pronghorn/blob/master/FindFUSE.cmake

Neither seem to work I get:

...argsparse.c:21:22: fatal error: fuse_opt.h: No such file or directory
 #include <fuse_opt.h>
                      ^
compilation terminated.

The python script works however which suggests there's something wrong with how cmake is configured.

For reference the pkg-config line above outputs the following on my system. -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse -lfuse -pthread

Thanks for any help!


Per Fraser's feed back I've update two things. My CMakeLists.txt now looks like:

cmake_minimum_required (VERSION 2.8.11)
project (HomeFS)

set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
    "${CMAKE_SOURCE_DIR}/CMakeModules/")

find_package(FUSE REQUIRED)

add_executable(homefs
    argsparse.c
    hidden.c
    initialization.c
    resolve.c
    utilities.c
    winhomefs0.4.c)

set(CMAKE_C_FLAGS "-D_FILE_OFFSET_BITS=64 -lulockmgr")

target_include_directories(homefs PRIVATE ${FUSE_INCLUDE_DIR})
target_link_libraries(homefs ${FUSE_LIBRARIES})

And all references to <fuse.h> and <fuse_opt.h> have been updated to <fuse/fuse.h> and so forth. I also had to add the flag -D_FILE_OFFSET_BITS=64 and it now compiles cleanly.

However I'm still getting a linker error.

winhomefs0.4.c:(.text+0x10b2): undefined reference to `ulockmgr_op'
collect2: error: ld returned 1 exit status

I tried adding the lib -lulockmgr to the c flags but that's not working. Google hasn't been my friend on this there are very few references to ulockmgr do I need to implement a FindULOCKMGR CMake module, or do I need to add the line elsewhere?


Ok after some trial and error + logical thought I solved the issue I needed to move the -lulockmgr string from CFLAGS to the target_link_libraries line.


Solution

  • You're probably just missing a couple of calls in your CMakeLists.txt.

    The line find_package(FUSE REQUIRED) will try and find the path to the FUSE headers and to the FUSE lib(s). The comment blocks at the top of the two FindFUSE.cmake files provide details of what variables each sets. Take the encfs one for example. It will set FUSE_FOUND to true or false, allowing you to exit your script with a helpful error message if FUSE isn't found.

    The variable FUSE_INCLUDE_DIR will be set to the absolute path of the folder containing the FUSE header. FUSE_LIBRARIES will be set to a list of absoulte paths to the FUSE libs.

    What's currently missing from your CMakeLists.txt is to use these variables.

    You would use them in calls to target_include_directories and target_link_libraries - e.g.

    target_include_directories(homefs PRIVATE ${FUSE_INCLUDE_DIR})
    target_link_libraries(homefs ${FUSE_LIBRARIES})
    

    Another issue is that you're creating five separate libraries with your five add_library calls, but then not using them. At the very least I'd have expected to see these also being linked to the exe via a target_link_libraries call.

    I don't know Python well enough to know what the original script is doing, but I think the more likely solution is that these should all just be part of the exe:

    add_library(argsparse argsparse.c) add_library(hidden hidden.c) add_library(initialization initialization.c) add_library(resolve resolve.c) add_library(utilities utilities.c) add_executable(homefs argsparse.c hidden.c initialization.c resolve.c utilities.c winhomefs0.4.c)