Search code examples
clinuxgnulibsndfilenyquist

How is the type sf_count_t in sndfile.h defined in libsndfile?


I am trying to work with Nyquist (a music programming platform, see: https://www.cs.cmu.edu/~music/nyquist/ or https://www.audacityteam.org/about/nyquist/) as a standalone program and it utilizes libsndfile (a library for reading and writing sound, see: http://www.mega-nerd.com/libsndfile/). I am doing this on an i686 GNU/Linux machine (Gentoo).

After successful set up and launching the program without errors, I tried to generate sound via one of the examples, "(play (osc 60))", and was met with this error:

*** Fatal error : sizeof (off_t) != sizeof (sf_count_t)
*** This means that libsndfile was not configured correctly.

Investigating this further (and emailing the author) has proved somewhat helpful, but the solution is still far from my grasp. The author recommended looking at /usr/include/sndfile.h to see how sf_count_t is defined, and (this portion of) my file is identical to his:

/* The following typedef is system specific and is defined when libsndfile is
** compiled. sf_count_t will be a 64 bit value when the underlying OS allows
** 64 bit file offsets.
** On windows, we need to allow the same header file to be compiler by both GCC
** and the Microsoft compiler.
*/

#if (defined (_MSCVER) || defined (_MSC_VER))
typedef __int64         sf_count_t ;
#define SF_COUNT_MAX          0x7fffffffffffffffi64
#else
typedef int64_t sf_count_t ;
#define SF_COUNT_MAX            0x7FFFFFFFFFFFFFFFLL
#endif

In the above the author notes there is no option for a "32 bit offset". I'm not sure how I would proceed. Here is the particular file the author of Nyquist recommend I investigate: https://github.com/erikd/libsndfile/blob/master/src/sndfile.h.in , and here is the entire source tree: https://github.com/erikd/libsndfile

Here are some relevant snippets from the authors email reply:

"I'm guessing sf_count_t must be showing up as 32-bit and you want libsndfile to use 64-bit file offsets. I use nyquist/nylsf which is a local copy of libsndfile sources -- it's more work keeping them up to date (and so they probably aren't) but it's a lot easier to build and test when you have a consistent library."

"I use CMake and nyquist/CMakeLists.txt to build nyquist."

"It may be that one 32-bit machines, the default sf_count_t is 32 bits, but I don't think Nyquist supports this option."

And here is the source code for Nyquist: http://svn.code.sf.net/p/nyquist/code/trunk/nyquist/

This problem is difficult for me to solve because it's composed of an niche use case of relatively obscure software. This also makes the support outlook for the problem a bit worrisome. I know a little C++, but I am far from confident in my ability to solve this. Thanks for reading and happy holidays to all. If you have any suggestions, even in terms of formatting or editing, please do not hesitate!


Solution

  • If you look at the sources for the bundled libsndfile in nyquist, i.e. nylsf, then you see that sndfile.h is provided directly. It defines sf_count_t as a 64-bit integer.

    The libsndfile sources however do not have this file, rather they have a sndfile.h.in. This is an input file for autoconf, which is a tool that will generate the proper header file from this template. It has currently the following definition for sf_count_t for linux systems (and had it since a while):

    typedef @TYPEOF_SF_COUNT_T@ sf_count_t ;
    

    The @TYPEOF_SF_COUNT_T@ would be replaced by autoconf to generate a header with a working type for sf_count_t for the system that is going to be build for. The header file provided by nyquist is therefore already configured (presumably for the system of the author).

    off_t is a type specified by the POSIX standard and defined in the system's libc. Its size on a system using the GNU C library is 32bit if the system is 32bit.

    This causes the sanity check in question to fail, because the sizes of sf_count_t and off_t don't match. The error message is also correct, as we are using an unfittingly configured sndfile.h for the build.

    As I see it you have the following options:

    1. Ask the nyquist author to provide the unconfigured sndfile.h.in and to use autoconf to configure this file at build time.

    2. Do not use the bundled libsndfile and link against the system's one. (This requires some knowledge and work to change the build scripts and header files, maybe additional unexpected issues)

    3. If you are using the GNU C library (glibc): The preprocessor macro _FILE_OFFSET_BITS can be set to 64 to force the size of off_t and the rest of the file interface to use the 64bit versions even on 32bit systems.

      This may or may not work depending on whether your system supports it and it is not a clean solution as there may be additional misconfiguration of libsndfile going unnoticed. This flag could also introduce other interface changes that the code relies on, causing further build or runtime errors/vulnerabilities.

      Nonetheless, I think the syntax for cmake would be to add:

      add_compile_definitions(_FILE_OFFSET_BITS=64)
      

      or depending on cmake version:

      add_definitions(-D_FILE_OFFSET_BITS=64)
      

      in the appropriate CMakeLists.txt.

    4. Actually the README in nyquist/nylsf explains how the files for it were generated. You may try to obtain the source code of the same libsndfile version it is based on and repeat the steps given to produce an nylsf configured to your system. It may cause less further problems than 2. and 3. because there wouldn't be any version/interface changes introduced.