%% 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.

% Copyright 2019 The MathWorks, Inc.

%% 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.
%
% <include>getGravityConst.m</include>
%
% 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.

