From 90bf3139476eeca5f47cfe2f72b78cc64353f4d0 Mon Sep 17 00:00:00 2001 From: simonpj Date: Mon, 13 Jan 2003 13:20:38 +0000 Subject: [PATCH] [project @ 2003-01-13 13:20:37 by simonpj] -------------------------------- Don't export the inlining for a foreign import that has a #include directive -------------------------------- Reason for this change: if the inlining is imported into another module, the latter may not have the right #include directives. Also add notes to the documentation to explain the issues. --- ghc/compiler/deSugar/DsForeign.lhs | 41 +++++++++++++++++++++++++++--------- ghc/docs/users_guide/ffi-chap.sgml | 32 +++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/ghc/compiler/deSugar/DsForeign.lhs b/ghc/compiler/deSugar/DsForeign.lhs index c5c4ded..c16cc86 100644 --- a/ghc/compiler/deSugar/DsForeign.lhs +++ b/ghc/compiler/deSugar/DsForeign.lhs @@ -120,30 +120,50 @@ dsFImport :: Id -> ForeignImport -> DsM ([Binding], SDoc, SDoc, [FastString]) dsFImport id (CImport cconv safety header lib spec) - = dsCImport id spec cconv safety `thenDs` \(ids, h, c) -> - returnDs (ids, h, c, if nullFastString header then [] else [header]) + = dsCImport id spec cconv safety no_hdrs `thenDs` \(ids, h, c) -> + returnDs (ids, h, c, if no_hdrs then [] else [header]) + where + no_hdrs = nullFastString header + -- FIXME: the `lib' field is needed for .NET ILX generation when invoking -- routines that are external to the .NET runtime, but GHC doesn't -- support such calls yet; if `nullFastString lib', the value was not given dsFImport id (DNImport spec) - = dsFCall id (DNCall spec) `thenDs` \(ids, h, c) -> + = dsFCall id (DNCall spec) True {- No headers -} `thenDs` \(ids, h, c) -> returnDs (ids, h, c, []) dsCImport :: Id -> CImportSpec -> CCallConv -> Safety + -> Bool -- True <=> no headers in the f.i decl -> DsM ([Binding], SDoc, SDoc) -dsCImport id (CLabel cid) _ _ +dsCImport id (CLabel cid) _ _ no_hdrs = ASSERT(fromJust resTy `eqType` addrPrimTy) -- typechecker ensures this - returnDs ([(id, rhs)], empty, empty) + returnDs ([(setImpInline no_hdrs id, rhs)], empty, empty) where (resTy, foRhs) = resultWrapper (idType id) rhs = foRhs (mkLit (MachLabel cid)) -dsCImport id (CFunction target) cconv safety - = dsFCall id (CCall (CCallSpec target cconv safety)) -dsCImport id CWrapper cconv _ +dsCImport id (CFunction target) cconv safety no_hdrs + = dsFCall id (CCall (CCallSpec target cconv safety)) no_hdrs +dsCImport id CWrapper cconv _ _ = dsFExportDynamic id cconv + +setImpInline :: Bool -- True <=> No #include headers + -- in the foreign import declaration + -> Id -> Id +-- If there is a #include header in the foreign import +-- we make the worker non-inlinable, because we currently +-- don't keep the #include stuff in the CCallId, and hence +-- it won't be visible in the importing module, which can be +-- fatal. +-- (The #include stuff is just collected from the foreign import +-- decls in a module.) +-- If you want to do cross-module inlining of the c-calls themselves, +-- put the #include stuff in the package spec, not the foreign +-- import decl. +setImpInline True id = id +setImpInline False id = id `setInlinePragma` NeverActive \end{code} @@ -154,7 +174,7 @@ dsCImport id CWrapper cconv _ %************************************************************************ \begin{code} -dsFCall fn_id fcall +dsFCall fn_id fcall no_hdrs = let ty = idType fn_id (tvs, fun_ty) = tcSplitForAllTys ty @@ -183,7 +203,8 @@ dsFCall fn_id fcall worker_ty = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty) the_ccall_app = mkFCall ccall_uniq fcall val_args ccall_result_ty work_rhs = mkLams tvs (mkLams work_arg_ids the_ccall_app) - work_id = mkSysLocal (encodeFS FSLIT("$wccall")) work_uniq worker_ty + work_id = setImpInline no_hdrs $ -- See comments with setImpInline + mkSysLocal (encodeFS FSLIT("$wccall")) work_uniq worker_ty -- Build the wrapper work_app = mkApps (mkVarApps (Var work_id) tvs) val_args diff --git a/ghc/docs/users_guide/ffi-chap.sgml b/ghc/docs/users_guide/ffi-chap.sgml index 4534b07..d3658e6 100644 --- a/ghc/docs/users_guide/ffi-chap.sgml +++ b/ghc/docs/users_guide/ffi-chap.sgml @@ -226,7 +226,6 @@ int main(int argc, char *argv[]) C calls, function headers When generating C (using the - directive), one can assist the C compiler in detecting type errors by using the directive () to provide @@ -256,6 +255,37 @@ HsInt lookupEFS (HsForeignObj a, HsInt i); Thing for anyone who cares about writing solid code. You're crazy not to do it. + +What if you are importing a module from another package, and +a cross-module inlining exposes a foreign call that needs a supporting +? If the imported module is from the same package as +the module being compiled, you should supply all the +that you supplied when compiling the imported module. If the imported module comes +from another package, you won't necessarily know what the appropriate + options are; but they should be in the package +configuration, which GHC knows about. So if you are building a package, remember +to put all those options into the package configuration. +See the c_includes field in . + + + +It is also possible, according the FFI specification, to put the + option in the foreign import +declaration itself: + + foreign import "#include foo.h f" f :: Int -> IO Int + +When compiling this module, GHC will generate a C file that includes +the specified . However, GHC +disables cross-module inlinding for such foreign +calls, because it doesn't transport the +information across module boundaries. (There is no fundamental reason for this; +it was just tiresome to implement. The wrapper, which unboxes the arguments +etc, is still inlined across modules.) So if you want the foreign call itself +to be inlined across modules, use the command-line and package-configuration + mechanism. + + -- 1.7.10.4