Hopsan
The Component Library Files

When you create a new component, you are actually creating a new component library. The library may contain one single component or multiple components. If you are creating multiple components, it is recommended to put them in the same library.

A Hopsan component library consists of at least three types of files.

  1. The compiled component library code as a .dll Windows (Dynamic Link Library) file, .so (Shared Object) file (Linux) or .dynlib file (Mac). Note! This guide will often refere to the .dll extension, even when .so or .dynlib is actually used.
  2. A .xml file at the library root level, containing the hopsancomponentlibrary information (optional but strongly recommended).
  3. A set of .xml files containing hopsanobjectappearance that describes the graphical appearance of each component.
  4. A set of .svg (Scalable Vector Graphics) files containing component icon graphics.

There needs to be one .xml file for every component in the library but .svg files can be shared if needed. All components should be compiled into one single .dll file. Subdirectories containing the component files can be used to create sub categories in the library.

If you have access to the component library source code, some additional important files should also be mentioned.

  1. A Qt project file .pro, used to generate a so called Makefile (build script) that is needed for building the code into the .dll.
    This file is only required if you build your library manually through QtCreator (or with qmake directly).
  2. One "libraryName".cpp file. This is the source code file that is compiled into the .dll.
  3. One or several "componentName".hpp files containing the source code of each individual component.

The header-only .hpp files contains the source code for each components, see Writing The Actual Component Code.
The .xml files contain the appearance description, and the .svg files are the icons, see Create or Modify Component Appearance.

The Hopsan Component Library Information File

This xml file, introduced in Hopsan version 0.7, contains the necessary information for Hopsan GUI to recognice which file is the component library .dll. This is required if a library in itself dependes on other third party libraries. The file also contains information necessary for automatic (re)compilation by Hopsan. This file is also used as the "project file" when editing component libraries from within Hopsan.

exampleComponentLib.xml

<?xml version="1.0" encoding="UTF-8"?>
<hopsancomponentlibrary version="0.2">
  <!-- The "id" element gives the library a unique identity, a UUID is recommended but any "unique" string is accepted -->
  <id>7f871523-08e4-4d68-a7e9-25860d861888</id>
  <!-- The 'name' element gives the library a human readable name that will be used in the library widget -->
  <name>HopsanExampleComponentLibrary</name>
  <!-- The "lib" element defines the name of the (.dll / .so / .dynlib) file, (without file extension) -->
  <!-- Use the "debug_ext" attribute to define the optional debug extension, used in debug mode -->
  <lib debug_ext="_d">examplecomponentlib</lib>
  <!-- Use one or more "source" elements to define the files that should be compiled and linked into the library -->
  <source>exampleComponentLib.cpp</source>
  <!-- The "buildflags" element can be used to specify optional compiler and linker flags necessary when compiling the library -->
  <buildflags>
    <!-- One or multiple "cflags" elements defines the compiler flags -->
    <!-- One or multiple "lflags" elements defines the linker flags -->
    <!-- use the "os" attribute to restrict the flag to a certain platform -->
    <!-- Example:  
    <cflags>-I./someLib/include</cflags>
    <lflags>-L./someLib/bin -lsomeLib</lflags>
    <lflags os="win64">-lWs2_32</lflags> -->
  </buildflags>
  <!-- Use one "component" element for every component source code .hpp (header only implementation) file -->
  <!-- This list of components will be used by the Hopsan library export code -->
  <component>HydraulicComponents/MyExampleConstantOrifice.hpp</component>
  <component>HydraulicComponents/MyExampleOrifice.hpp</component>
  <component>HydraulicComponents/MyExampleVolume.hpp</component>
  <component>HydraulicComponents/MyExampleVolume2.hpp</component>
  <component>SignalComponents/MyExampleSignalSum.hpp</component>
  <!-- Use one "componentxml" element for every component description XML file -->
  <componentxml>SignalComponents/MyExampleSignalSum.xml</componentxml>
  <componentxml>HydraulicComponents/MyExampleConstantOrifice.xml</componentxml>
  <componentxml>HydraulicComponents/MyExampleOrifice.xml</componentxml>
  <componentxml>HydraulicComponents/MyExampleVolume.xml</componentxml>
  <componentxml>HydraulicComponents/MyExampleVolume2.xml</componentxml>
</hopsancomponentlibrary>

The Qt Project File

This is the project file used by Qt Creator. It is used by qmake to generate a Makefile (compilation script). If you are using a different coding environment, you need to create a similar file for that environment. It is also possible to write a custom Makefile manually. It basically comes down to specifying the include path to the HopsanCore include files and the link path to the pre-compiled HopsanCore shared object (.dll, .so, .dynlib) file or link library (.lib, .a).

A few modifications are required in this file. First of all the INCLUDEPATH must be changed so that it points to the "include" folder of the HopsanCore installation. Similarly, the LIBS path must point to the "bin" folder in the installation directory. You should also change the TARGET to the name you wish your compiled library (.dll) to have. Finally, the relative path to all components source files in the library must be specified under HEADERS. (Assuming you have written each component in a header-only file).

exampleComponentLib.pro

# QT -= core gui, means that we should not link the default qt libs into the component
# Template = lib, means that we want to build a library (.dll or .so)
QT -= core gui
TEMPLATE = lib

# TARGET is the name of the compiled lib, (.dll or .so will be added automatically)
# Change this to the name of YOUR lib
TARGET = examplecomponentlib

# Destination for the compiled dll. $${PWD}/ means the same directory as this .pro file, even if you use shadow build
DESTDIR = $${PWD}/

# The location to search for the Hopsan include files. By specifying the path here, you dont need to
# do this in each of your component .hpp files. You can also add additional paths for any custom Utility functions,
# just add additional INCLUDEPATH *= ... lines.
# *= Means append unique
INCLUDEPATH *= $${PWD}/../../HopsanCore/include/
#INCLUDEPATH *= "C:/SomeDirectoryPath/Hopsan/HopsanCore/include/"

# The location of the HopsanCore .dll or .so file, needed to link against when compiling your library
LIBS *= -L$${PWD}/../../bin
#LIBS *= -L"C:/SomeDirectoryPath/Hopsan/bin/"

# Special options for deug and release mode. This will link the correct HopsanCore .dll or .so
# In debug mode HopsanCore has the debug extension _d
include(hopsanDebugReleaseCompile.pri)

# Reduce compile output clutter, but show warnings
CONFIG += silent warn_on

# The compiler should be pedantic to catch all errors (optional)
QMAKE_CXXFLAGS += -pedantic

# Enable C++14
CONFIG += c++14

# Enable the use of M_PI and such
DEFINES *= _USE_MATH_DEFINES

# -------------------------------------------------
# Project files
# -------------------------------------------------
SOURCES += \
    exampleComponentLib.cpp

HEADERS += \
    HydraulicComponents/MyExampleVolume.hpp \
    HydraulicComponents/MyExampleOrifice.hpp \
    SignalComponents/MyExampleSignalSum.hpp \
    HydraulicComponents/MyExampleVolume2.hpp \
    HydraulicComponents/MyExampleConstantOrifice.hpp

OTHER_FILES += \
    hopsanDebugReleaseCompile.pri

The Component Library Source File

This file contains code that is used to register you library components in the HopsanCore. A few modifications are required.

  1. First of all, all component header code files must be included. (The #include directive will actually in-place copy the included files into the cpp file prior to compilation)
  2. Second, each component needs to be registered in the HopsanCore by the "`pComponentFactory->registerCreatorFunction("KeyValue", CreatorFunction)`" lines.
    The "KeyValue" argument must be a unique TypeName that identifies you component. The CreatorFunction argument is the Creator() function the must exist in each component.
  3. Third, Make sure that you write a unique libName (as a string) in the get_hopsan_info function. Leave the two last lines as they are.

exampleComponentLib.cpp

http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The full license is available in the file LICENSE.
For details about the 'Hopsan Group' or information about Authors and
Contributors see the HOPSANGROUP and AUTHORS files that are located in
the Hopsan source code root directory.
-----------------------------------------------------------------------------*/
// Include your component code code files here
// If you have lots of them you can include them in separate .h files and then include those files here instead.
#include "HydraulicComponents/MyExampleOrifice.hpp"
#include "HydraulicComponents/MyExampleConstantOrifice.hpp"
#include "HydraulicComponents/MyExampleVolume.hpp"
#include "HydraulicComponents/MyExampleVolume2.hpp"
#include "SignalComponents/MyExampleSignalSum.hpp"
// You need to include ComponentEssentials.h in order to gain access to the register function and the Factory types
// Also use the hopsan namespace
#include "ComponentEssentials.h"
using namespace hopsan;
// When you load your model into Hopsan, the register_contents() function bellow will be called
// It will register YOUR components into the Hopsan ComponentFactory
extern "C" DLLEXPORT void register_contents(ComponentFactory* pComponentFactory, NodeFactory* pNodeFactory)
{
// ========== Register Components ==========
// Use the registerCreatorFunction(KeyValue, Function) in the component factory to register components
// The KeyValue is a text string with the TypeName of the component.
// This value must be unique for every component in Hopsan.
// If a typename is already in use, your component will not be added.
// Suggestion, let the KeyValue (TypeName) be the same as your Class name
// If that name is already in use, use something similar
pComponentFactory->registerCreatorFunction("MyExampleOrifice", MyExampleOrifice::Creator);
pComponentFactory->registerCreatorFunction("MyExampleConstantOrifice", MyExampleConstantOrifice::Creator);
pComponentFactory->registerCreatorFunction("MyExampleVolume", MyExampleVolume::Creator);
pComponentFactory->registerCreatorFunction("MyExampleVolume2", MyExampleVolume2::Creator);
pComponentFactory->registerCreatorFunction("MyExampleSignalSum", MyExampleSignalSum::Creator);
// ========== Register Custom Nodes (if any) ==========
// This is not yet supported
HOPSAN_UNUSED(pNodeFactory)
}
// When you load your model into Hopsan, the get_hopsan_info() function bellow will be called
// This information is used to make sure that your component and the hopsan core have the same version
extern "C" DLLEXPORT void get_hopsan_info(HopsanExternalLibInfoT *pHopsanExternalLibInfo)
{
// Change the name of the lib to something unique
// You can include numbers in your name to indicate library version (if you want)
pHopsanExternalLibInfo->libName = (char*)"HopsanExampleComponentLibrary";
// Leave these two lines as they are
pHopsanExternalLibInfo->hopsanCoreVersion = (char*)HOPSANCOREVERSION;
pHopsanExternalLibInfo->libCompiledDebugRelease = (char*)HOPSAN_BUILD_TYPE_STR;
}
hopsan::ClassFactory
Template class for automatic object instantiation by key-value.
Definition: ClassFactory.hpp:50
hopsan::ClassFactory::registerCreatorFunction
void registerCreatorFunction(const _Key &rIdKey, CreatorFunctionT classCreator)
Used to register creator functions.
Definition: ClassFactory.hpp:68