Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use LibC #366

Open
TravisCardwell opened this issue Jan 17, 2025 · 1 comment
Open

Use LibC #366

TravisCardwell opened this issue Jan 17, 2025 · 1 comment

Comments

@TravisCardwell
Copy link
Collaborator

Discussing with @edsko, we need to start using the LibC module in the code that we generate.

When translating C code, we must be able to recognize when a C type is one of the standard types that we support. Such types include the following:

  • Standard types defined in base in Foreign.**
  • stdint types that map to Haskell types defined in base in Data.Int and Data.Word
  • Standard types that we define in HsBindgen.Runtime.LibC

A known C type is mapped to a Haskell package, module, and identifier. Making such a mapping implementation general would be useful, since it could be used if/when we add support for translating multiple headers/modules.

Perhaps we can identify standard types using the name and source location information provided by libclang. Note that the actual source header files for many types may differ in different C library implementation, since they have different internal implementations. For example, Musl defines many types in the bits/alltypes.h header file that is included by the standard header files.

@edsko has a promising idea: perhaps we can parse our standard_headers.h bootstrap file and keep track of where the standard types are defined in that execution (which depends on which include directories are configured). We could then use the results to identify standard types as we translate the user code. With this idea, the implementation details should not matter, and we do not need to worry about the same types being imported from different header files.

If we run into trouble, perhaps we can build up a call-stack-style "include stack." I think we can do this with the information provided by libclang while folding, but we could parse the tokens of include directives if necessary.

Should we add checks to confirm that a parsed standard type matches the Haskell definition/instances? We could check that size and alignment are consistent. We could check that structure/union field names and types are consistent.

@TravisCardwell
Copy link
Collaborator Author

Types may be defined differently in different C library implementations.

For example, on my platform, using my default system (glibc) include path:

typedef signed int __int32_t;  // /usr/include/bits/types.h
typedef __int32_t int32_t;     // /usr/include/bits/stdint-intn.h

Using Musl:

typedef signed int int32_t;    // hs-bindgen/musl-include/x86_64/bits/alltypes.h

We need to map the C int32_t to Haskell Data.Int.Int32 for all such definitions.


Details:

Test header:

#include <stdint.h>

typedef int32_t MyInt32;

Using my default system include path:

$ cabal run hs-bindgen -- dev parse --input travis.h
Header
  { headerDecls =
      [ DeclTypedef
          Typedef
            { typedefName = CName { getCName = __int32_t }
            , typedefType = TypePrim (PrimIntegral PrimInt Signed)
            , typedefSourceLoc = "/usr/include/bits/types.h:41:20"
            }
      , DeclTypedef
          Typedef
            { typedefName = CName { getCName = int32_t }
            , typedefType = TypeTypedef CName { getCName = __int32_t }
            , typedefSourceLoc = "/usr/include/bits/stdint-intn.h:26:19"
            }
      , DeclTypedef
          Typedef
            { typedefName = CName { getCName = MyInt32 }
            , typedefType = TypeTypedef CName { getCName = int32_t }
            , typedefSourceLoc = "travis.h:3:17"
            }
      ]
  }

Using the vendored Musl headers:

$ cabal run hs-bindgen -- \
    --clang-option='-nostdinc' \
    --clang-option="-isystem$(pwd)/hs-bindgen/musl-include/x86_64" \
    dev parse --input travis.h
Header
  { headerDecls =
      [ DeclTypedef
          Typedef
            { typedefName = CName { getCName = int32_t }
            , typedefType = TypePrim (PrimIntegral PrimInt Signed)
            , typedefSourceLoc =
                "hs-bindgen/musl-include/x86_64/bits/alltypes.h:106:25"
            }
      , DeclTypedef
          Typedef
            { typedefName = CName { getCName = MyInt32 }
            , typedefType = TypeTypedef CName { getCName = int32_t }
            , typedefSourceLoc = "travis.h:3:17"
            }
      ]
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant