%% Integrate Multiple Generated C++ Code Projects
% This example shows how to integrate two different generated C++ code projects into a single, larger project.
% Your generated code projects might have similar function names, but have different settings, parameters, or functionality. Generate code with namespaces to aid in integrating different projects that share the same names. Namespaces can also improve code readability.
%% Generate C++ Code for a MATLAB® Algorithm
% Consider a simple MATLAB function that returns a gravitational constant. The value of the gravitational constant is derived from a global variable.

type getGravityConst.m

% Suppose that you want to generate code for getGravityConst that models scenarios for the Moon and for the Earth. Generate two separate code projects with the same entry-point function. Specify a different global value, and hence, gravitational constant, for each project.
% Create a code generation configuration object. Specify:
% DLL build type.
% C++ target language.
% The name of the orbital body as the namespace.
% #pragma once style #include guards.
% Packaging of the generated code files into a  .zip file by calling the packNGo function.

cfg = coder.config('dll');
cfg.TargetLang = "C++";
cfg.CppNamespace = 'moon';
cfg.HeaderGuardStyle = "UsePragmaOnce";
cfg.PostCodeGenCommand = 'packNGo(buildInfo)';

%
% Generate code for getGravityConst to model the Moon:
% By using the previously defined configuration object.
% With a code generation report.
% Such that the code returns the Moon's value of the gravitational constant in units of m/s^2.
% In an output folder called projectMoon.
% With output binaries called getGravityConstMoon.

codegen getGravityConst -config cfg -report -globals {'g', -1.62} ...
    -d projectMoon -o getGravityConstMoon

%
% To generate code for getGravityConst that models the earth, first modify the:
% Namespace name
% Gravitational constant
% Output file name
% Output folder name

cfg = coder.config('dll');
cfg.TargetLang = "C++";
cfg.CppNamespace = 'earth';
cfg.HeaderGuardStyle = "UsePragmaOnce";
cfg.PostCodeGenCommand = 'packNGo(buildInfo)';

codegen getGravityConst -config cfg -report -globals {'g', -9.81} ...
    -d projectEarth -o getGravityConstEarth

%
%% Project Integration Scenario: Planetary Modeling
% Suppose that you want to design a larger project that performs planetary modeling and computes quantities such as the flight times of falling objects. The flight time depends on the gravitational constant for each planet and the initial height of the object. You want to use the generated code functions for getGravityConst in this larger project.
%% Determine the Platform-Dependent File Extensions
% The generated dynamic libraries have different extensions on different platforms. This code determines the correct extensions for your platform.

dllext = '';
libext = '';
if ismac
    dllext = '.dylib';
    libext = dllext;
elseif isunix
    dllext = '.so';
    libext = dllext;
elseif ispc
    dllext = '.dll';
    libext = '.lib';
else
    disp('Platform not supported')
    return
end

%
%% Write a Main File That Uses the Generated Code Projects
% In the general case, you integrate different projects by writing or modifying a main file to call each of the projects' functions. By using namespaces, you can distinguish the generated functions for each project, even though the function names are the same.
% For an example of how to write a main file that uses the generated C++ code for both projects, see the attached file main_planetSim.cpp. To build an executable or binary from the main file, you must specify or provide the following to the build tools (compiler, linker, and/or IDE) and their correct paths:
% Header files for any called functions.
% On Windows platforms, import libraries (.lib files).
% Dynamic libraries (.dll, .so and .dylib files).
% Include directories for other generated source and include files.
% The .zip files that the packNGo command creates during code generation contain the generated code files. Unpack the zip files to folders in your build directory or build environment. You must also make your dynamic libraries accessible to the executable, for example, by moving the generated dynamic libraries to the same folder as the executable.
%% Write a MATLAB Function that Integrates the Two Projects
% As an alternative to writing a main file by hand, you can also integrate two projects into a third generated code project by using the coder.ceval function. The coder.ceval function enables you to call external C/C++ code from generated C/C++ code.
% The file planetSim.m shows how to use coder.ceval and associated build configuration functions to integrate the generated projects into the larger project.
% <include>planetSim.m</include>
% Generate MEX code for the planetSim function:

linkObjectMoon = ['projectMoon/getGravityConstMoon' libext];
linkObjectEarth = ['projectEarth/getGravityConstEarth' libext];

cfg = coder.config('mex');
cfg.TargetLang = "C++";
codegen('planetSim','-config',cfg,'-d','planetSim','-report',linkObjectMoon,linkObjectEarth)

%
%% Test the Generated MEX Function
% Use the MEX function to test the generated code in the MATLAB environment. The MEX function must have access to the generated link libraries. Move the link libraries to the current directory and call the MEX function.

copyfile(['projectMoon/getGravityConstMoon' dllext]);
copyfile(['projectEarth/getGravityConstEarth' dllext]);

[t_m, t_e] = planetSim_mex

%
% The output shows the flight times for the falling object on the Moon and on the Earth.
% Copyright 2019 The MathWorks, Inc.