[project @ 2003-01-13 13:20:37 by simonpj]
authorsimonpj <unknown>
Mon, 13 Jan 2003 13:20:38 +0000 (13:20 +0000)
committersimonpj <unknown>
Mon, 13 Jan 2003 13:20:38 +0000 (13:20 +0000)
--------------------------------
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
ghc/docs/users_guide/ffi-chap.sgml

index c5c4ded..c16cc86 100644 (file)
@@ -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
index 4534b07..d3658e6 100644 (file)
@@ -226,7 +226,6 @@ int main(int argc, char *argv[])
       <indexterm><primary>C calls, function headers</primary></indexterm>
 
       <para>When generating C (using the <option>-fvia-C</option>
-
       directive), one can assist the C compiler in detecting type
       errors by using the <option>-&num;include</option> directive
       (<xref linkend="options-C-compiler">) 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.</para>
 
+<para>
+What if you are importing a module from another package, and
+a cross-module inlining exposes a foreign call that needs a supporting
+<option>-&num;include</option>?  If the imported module is from the same package as
+the module being compiled, you should supply all the <option>-&num;include</option>
+that you supplied when compiling the imported module.  If the imported module comes
+from another package, you won't necessarily know what the appropriate 
+<option>-&num;include</option> 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 <option>-&num;include</option> options into the package configuration.
+See the <literal>c_includes</literal> field in <xref linkend="package-management">.
+</para>
+
+<para>
+It is also possible, according the FFI specification, to put the 
+<option>-&num;include</option> option in the foreign import 
+declaration itself:
+<programlisting>
+  foreign import "#include foo.h f" f :: Int -> IO Int
+</programlisting>
+When compiling this module, GHC will generate a C file that includes
+the specified <option>-&num;include</option>.  However, GHC
+<emphasis>disables</emphasis> cross-module inlinding for such foreign
+calls, because it doesn't transport the <option>-&num;include</option>
+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
+<option>-&num;include</option> mechanism.
+</para>
+
     </sect2>
   </sect1>
 </Chapter>