classdef (Hidden=true) Writer < handle
% Class that represents a build artifact writer.

% Copyright 2012-2019 The MathWorks, Inc.

properties
Parent
Components

Artifacts
ArtifactType = [];

IsArtifactWrapped
end

properties(SetAccess = immutable)
ToolchainInfo
BuildOpts
BuildConfiguration
WrMakefileName
end

% -----------------------
% ABSTRACT METHODS
% -----------------------
methods (Abstract)
% -----------------------------------------------------------------
% Each concrete Writer must implement a RUN method. The by-product
% of this is the build artifact.
% -----------------------------------------------------------------
run(h, buildInfoW);

end % abstract methods

% -----------------------
% GET/SET METHODS
% -----------------------
methods

% function set.ToolchainInfo(h, value)
% if ~isempty(value) && ~isa(value, 'coder.make.ToolchainInfo')
% error(message('CoderFoundation:utility:InvalidProperty', ...
% 'ToolchainInfo', class(h), 'coder.make.ToolchainInfo'))
% end
% h.ToolchainInfo = value;
% end
%
% function set.BuildOpts(h, value)
% if ~isempty(value) && ~isstruct(value)
% error(message('CoderFoundation:utility:InvalidProperty', ...
% 'BuildOpts', class(h), 'struct'))
% end
% h.BuildOpts = value;
% end

function set.Components(h, value)
if ~isempty(value) && ~isstruct(value)
error(message('CoderFoundation:utility:InvalidProperty', ...
'Components', class(h), 'struct'))
end
h.Components = value;
end

function set.Artifacts(h, value)
if ~isempty(value) && ~iscell(value) %% ~iscellstr(value)
error(message('CoderFoundation:utility:InvalidProperty', ...
'Artifacts', class(h), 'cell array of strings'))
end
h.Artifacts = value;
end

% function set.ArtifactWrapper(h, value)
% if ~isempty(value) && ~ischar(value)
% error(message('CoderFoundation:utility:InvalidProperty', ...
% 'ArtifactWrapper', class(h), 'string'))
% end
% h.ArtifactWrapper = value;
% end

function set.ArtifactType(h, value)
if ~isempty(value) && ~isa(value, 'coder.make.enum.BuildArtifact')
error(message('CoderFoundation:utility:InvalidProperty', ...
'ArtifactType', class(h), 'coder.make.enum.BuildArtifact'))
end
h.ArtifactType = value;
end

end % get/set methods

% -----------------------
% PUBLIC METHODS
% -----------------------
methods (Access = public)

% -----------------------------------------------------------------
% Constructor
% -----------------------------------------------------------------
function h = Writer(builder, buildInfo)
h.Parent = builder;
h.ToolchainInfo = h.Parent.ToolchainInfo;
h.Components = h.Parent.Components;
h.BuildOpts = buildInfo.getBuildToolInfo('BuildOpts');
h.BuildConfiguration = builder.BrBuildConfiguration;
h.WrMakefileName = builder.BrMakefileName;

h.Artifacts = '';
h.ArtifactType = h.ToolchainInfo.BuildArtifactType; % the toolchain knows what artifact it can create
h.IsArtifactWrapped = 0;
% h.ArtifactWrapper = [];
end

% -----------------------------------------------------------------
% Get the designated macro for a specific build entity
% -----------------------------------------------------------------
function macro = getMacro(h, type) %#ok<INUSL>
macro = coder.make.Writer.getMacroOf(type);
end
end

% -----------------------
% STATIC METHODS
% -----------------------
methods(Static, Hidden)

% -----------------------------------------------------------------
% Macros used for each known component in the build artifact
% -----------------------------------------------------------------
function macro = getMacroOf(type)
switch lower(type)
case {'sources', 'source files'}
macro = 'SRCS';
case 'main source file'
macro = 'MAIN_SRC';
case 'all source files'
macro = 'ALL_SRCS';
case {'mex source', 'mex source file'}
macro = 'MEX_SRC';
case {'modules'}
macro = 'MODULES';
case 'include files'
macro = 'HDRS';
case {'includes', 'include paths'}
macro = 'INCLUDES';
case 'defines'
macro = 'DEFINES';
case {'libraries', 'library files'}
macro = 'LIBS';
case {'modelref libraries'}
macro = 'MODELREF_LIBS';
case {'link libraries'}
macro = 'LINK_LIBS';
case {'objects', 'object files'}
macro = 'OBJS';
case 'main object file'
macro = 'MAIN_OBJ';
case {'all object files'}
macro = 'ALL_OBJS';
case 'prebuilt object files'
macro = 'PREBUILT_OBJS';
case {'syslibs'}
macro = 'SYSTEM_LIBS';
case {'toolchainlibs'}
macro = 'TOOLCHAIN_LIBS';
case {'product', 'product file', 'output file'}
macro = 'PRODUCT';
case 'product type'
macro = 'PRODUCT_TYPE';
case 'build type'
macro = 'BUILD_TYPE';
case 'toolchain file'
macro = 'TOOLCHAIN_MAKEFILE';
case 'shared util'
macro.srcs = 'SHARED_SRC';
macro.objs = 'SHARED_OBJS';
macro.objs_no_path = 'SHARED_OBJS_NO_PATH';
macro.bin_path = 'SHARED_BIN_DIR';
otherwise
error(message('CoderFoundation:builder:UnknownArtifactComponent', type))
end
end
function value = transformPaths(value, ~)
end
end

% -----------------------
% HELPER METHODS
% -----------------------
methods (Hidden)

% -----------------------------------------------------------------
% Concatenate a cell array of strings
% -----------------------------------------------------------------
function strOut = concatenate(h, strIn, delimiter) %#ok<INUSL>
if nargin==2
delimiter = ' ';
end
strOut = '';
if ischar(strIn)
strOut = strIn;
return; % nothing to concatenate
elseif iscell(strIn) %% iscellstr(strIn)
if isempty(strIn)
return;
end
strOut = strIn{1};
for i=2:numel(strIn)
strOut = [strOut delimiter strIn{i}]; %#ok<AGROW>
end
elseif isempty(strIn)
strOut = '';
else
error(message('CoderFoundation:utility:InvalidInputTypeToFunction', ...
'2', 'Writer::concatenate()', 'string or cell array of strings'));
end
end

% -----------------------------------------------------------------
% Wrap a makefile string
% Example:
% Before: CFLAGS = -c -O2 $(C_STANDARD_OPTS) $(OPTIM_OPTS)
% After: CFLAGS = -c -O2 $(C_STANDARD_OPTS) \
% $(OPTIM_OPTS)
% -----------------------------------------------------------------
function strOut = wrapString(h, strIn)
maxCharWidth = 60;
if numel(strIn) > maxCharWidth
space = ' ';
spaces = strfind(strIn, space);
idx = find(spaces<maxCharWidth);
if isempty(idx)
strOut = strIn; % no spaces, string cannot be cut
return;
else
idx = idx(end);
strOut = [strIn(1:idx) h.ToolchainInfo.getBuilderApplication().getLineContinuator()];
strIn = strIn(idx+1:end);
while ~strcmpi(strOut, strIn)
strOut = wrapString(h, strIn); % TODO: STOPPED HERE
end
end
else
strOut = strIn;
return;
end
end

end % hidden methods

end

% LocalWords: Toolchain toolchain HDRS OBJS prebuilt syslibs toolchainlibs
% LocalWords: CFLAGS