-> 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}
%************************************************************************
\begin{code}
-dsFCall fn_id fcall
+dsFCall fn_id fcall no_hdrs
= let
ty = idType fn_id
(tvs, fun_ty) = tcSplitForAllTys ty
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
<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>-#include</option> directive
(<xref linkend="options-C-compiler">) to provide
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>-#include</option>? If the imported module is from the same package as
+the module being compiled, you should supply all the <option>-#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>-#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>-#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>-#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>-#include</option>. However, GHC
+<emphasis>disables</emphasis> cross-module inlinding for such foreign
+calls, because it doesn't transport the <option>-#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>-#include</option> mechanism.
+</para>
+
</sect2>
</sect1>
</Chapter>