Package Import and Export for C++ New Toolchain

From RAD Studio
Jump to: navigation, search

Go Up to Packages for C++ New Toolchain


Using the PACKAGE or __declspec(package) modifier, it can be complex to understand when items are imported or exported. RAD Studio applies heuristics and defined that a class is treated as declspec(dllexport) when the clauses below are met:

  • The class is marked as __declspec(package) and contains a non-inline function declaration.
  • The file containing the class is compiled with the -tP option.

Otherwise, the class is considered declspec(dllimport).

In other words, this guesses. There is no good way to map a declaration in a C++Builder header file to know when it should be exported or imported. So we apply heuristics. In general, seeing a PACKAGE macro assumes the package is trying to export it when building a package project, otherwise it is importing.

Note that we use inline methods ourselves in our HPP files. These methods are usually for constructors, due to differences in constructor availability in descendant classes (Delphi inherits all constructors). Yet, these methods do not prevent a class from being imported according to the heuristics. The takeaway here is the application of heuristics when using __declspec(package).

This is all because packages try to map a Delphi concept to C++Builder, and it cannot be done perfectly. In general, RAD Studio recommends you use packages carefully. Use cases that map to Delphi (such as components) are far more likely to be successful than using a package as a kind of DLL, when you should instead use a DLL or static library.

Code sample

class PACKAGE TMyComponent : public TComponent {
public:
    __fastcall TMyComponent(TComponent* Owner);
    void __fastcall DoSomething();
};

In this example, the TMyComponent class has the PACKAGE macro (which expands to decspec(package).) As a result, the compiler applies heuristics to determine whether you are trying to export or import the class.

Recommendations

Please review the recommendation below when using the package import and export for the new C++ toolchain, these will help you prevent issues.

  • We strongly advise against using compiler-default or compiler-generated methods for your package-marked class. Follow the rule of three/five.
  • Under any circumstances, do not use inline methods in your imported or exported package types, even if they are simple. Explicitly, specifically, place all methods (including constructor/destructor/copy constructor, and others) in the .cpp file.
  • We strongly recommend not to export any template types, as they are inlined by definition and may result in multiple definitions.
  • Be careful with dependencies between units, and familiarize yourself with unit initialization and finalization.
  • We strongly recommend as a general practice not using PACKAGE or __declspec(package) at all for anything other than trivial cases. Instead, we advise tagging manually your types with __declspec(dllimport) and __declspec(dllexport).
    Tip: A possible approach is to wrap the modifiers in a macro whose value depends on the location of the header. In other words, your EXE project might define a macro so that when the header is included you always import it.
  • Packages are extended DLLs thus these dllimport/dllexport directives apply. The key here is that by explicitly marking them, there is no guesswork performed by the compiler, but a clear directive from the programmer to try to export or import. Packages are great for components and useful for Delphi-based types, but in general, we recommend using DLLs with the dynamic runtime.
    Attention: Note that C++ has no type rooting across modules.

See Also