function buildInfo = create_build_info(fileNameInfo)
% Create an RTW.BuildInfo object to and populate it with the data in
% fileNameInfo structure.

%   Copyright 2012-2019 The MathWorks, Inc.

global gMachineInfo gTargetInfo;

if ~gTargetInfo.codingSFunction
    buildInfo = '';
    return;
end

buildInfo = gTargetInfo.buildInfo;
linkFlags = '';
compilerName = '.';
compileFlags = '';
compilerSpecificSrc = {};
compilerSpecificPath = {};
includePaths = {};
includePathsGroup = {};

libFiles = {};
libPaths = {};
libGroup = {};

%Setup compiler and linker flags
userCflags = strtrim([fileNameInfo.customUserDefines ' ' fileNameInfo.customCompilerFlags]);
if isunix
    if gTargetInfo.codingFasterRun
        compileFlags = [compileFlags ' -O2'];
    end
    if(gTargetInfo.codingOpenMP)
        userCflags = [userCflags ' -fopenmp -fPIC'];
    end
    if ismac
        linkFlags = '-Wl,-rpath,@loader_path ';
    end
    if ~isempty(userCflags)
        compileFlags = [compileFlags ' ' userCflags];
    end
elseif gTargetInfo.codingMSVCMakefile
    compileFlags = '/c /Zp8 /GR /W3 /EHs /D_CRT_SECURE_NO_DEPRECATE /D_SCL_SECURE_NO_DEPRECATE /D_SECURE_SCL=0 /DMX_COMPAT_64 /DMATLAB_MEXCMD_RELEASE=R2018a /DMATLAB_MEX_FILE /nologo /MD';
    compileFlags = [compileFlags ' ' userCflags];
    if gTargetInfo.codingOpenMP
        compileFlags = [compileFlags ' /openmp'];
    end
    if gTargetInfo.codingFasterRun
        compileFlags = ['/O2 ' compileFlags];
    end
    linkFlags = '/nologo /dll /MANIFEST /OPT:NOREF /export:mexFunction /export:mexfilerequiredapiversion ';
    compilerName = 'microsoft';
elseif gTargetInfo.codingMinGWMakefile
    compilerName = 'mingw64';
    if gTargetInfo.codingFasterRun
        compileFlags = [compileFlags ' -O2'];
    end
    if ~isempty(userCflags)
        compileFlags = [compileFlags ' ' userCflags];
    end
elseif gTargetInfo.codingLccMakefile
    if(strcmp(computer,'PCWIN64'))
        lccRoot = fullfile(matlabroot,'sys','lcc64','lcc64');
        compilerName = 'microsoft'; %LCC64 is using microsoft libraries.

		compileFlags = '-dll -noregistrylookup  -c -Zp8 -DLCC_WIN64 -DMATLAB_MEX_FILE -nodeclspec';
        compileFlags = [compileFlags ' ' userCflags];
		linkFlags = ['-dll',' -L"',lccRoot,'\lib64" -entry LibMain -map sfun.map'];
		if gTargetInfo.codingMakeDebug
		    % Add -g2 to add debug info
			compileFlags = ['-g2 ',compileFlags];
		else
			% -s strips out the debug info
			linkFlags = ['-s ',linkFlags];
		end
        defFileName = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.def'];
        if(gTargetInfo.codingLibrary)
            mexFileName = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.lib'];
        else
            mexFileName= [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.',mexext];
        end
        str = ['LIBRARY ',mexFileName,10,...
            'EXPORTS',10,...
            'mexFunction', 10, ...
            'mexfilerequiredapiversion'];
        sfprivate('str2file',str,fullfile(fileNameInfo.targetDirName,defFileName));
        includePaths{end+1} = fullfile(lccRoot,'include64');
    else
    lccRoot =  fullfile(matlabroot,'sys','lcc');
        compilerName = 'lcc';

    if gTargetInfo.codingMakeDebug
        compileFlags = '-g4 -c -Zp8 -DMATLAB_MEX_FILE -noregistrylookup';
		linkFlags = ['-dll',' -L"',lccRoot,'\lib"'];
	else
		compileFlags = '-c -Zp8 -DMATLAB_MEX_FILE -noregistrylookup';
		linkFlags = ['-s -dll',' -L"',lccRoot,'\lib"'];
    end
        defFileName = [lccRoot,'\mex\lccdef.def'];
        includePaths{end+1} = fullfile(lccRoot,'include');

    end

    includePathsGroup{end+1} = 'LCC';
    if ~gTargetInfo.codingLibrary
        compilerSpecificSrc{1} = 'lccstub.c';
        compilerSpecificPath{1} = fullfile(lccRoot,'mex');
        [libPaths{end+1}, libFiles{end+1}, extLib] = fileparts(defFileName);
        libFiles{end} = [libFiles{end} extLib];
        libGroup{end+1} = 'LCC_DEF';
    end
end

%Get user specified compile and Link Flags
linkFlags = [linkFlags ' ' fileNameInfo.customLinkerFlags];

buildInfo.addCompileFlags(compileFlags,'OPTS')
%LDFLAGS
buildInfo.addLinkFlags(linkFlags,'CCLinkFlags');

MLROOT = buildInfo.Settings.Matlabroot;


%Add paths to be included to the buildInfo'
%ML_INCLUDES, SL_INCLUDES, SF_INCLUDES, USER_INCLUDES,AUX_INCLUDES
%------------------------------------------|-----------------------|
%            IncludePath                   |  Group                |
%                                          |                       |

if gTargetInfo.codingMSVCMakefile || gTargetInfo.codingLccMakefile
    % We cannot fix this in create_file_name_info() since the targetDirName field is used not only for makefiles.
    targetDirNameFixed = CGXE.Utils.fix_windows_paths_for_make_file(fileNameInfo.targetDirName);
else
    targetDirNameFixed = fileNameInfo.targetDirName;
end

includeInfo =  [ ...
    {fullfile(MLROOT,'extern','include');    'ML_INCLUDES'}, ...
    {fullfile(MLROOT,'simulink','include');  'SL_INCLUDES'}, ...
    {fullfile(MLROOT,'simulink','include','sf_runtime');  'SL_INCLUDES'}, ...
    {fileNameInfo.rtwHeadersInclude;         'SF_INCLUDES'},...
    {fileNameInfo.sfRuntimeIncludeDir;       'SF_INCLUDES'},...
    {fullfile(MLROOT,'rtw','c','src');       'SL_INCLUDES'}, ...
    {targetDirNameFixed;                     'SF_INCLUDES'}, ...
    [fileNameInfo.userIncludeDirs;           repmat({'USER_INCLUDES'},size(fileNameInfo.userIncludeDirs))]...
    [fileNameInfo.auxInfo.includePaths;      repmat({'AUX_INCLUDES'},size(fileNameInfo.auxInfo.includePaths))]...
    ];

if fileNameInfo.hasSLCCCustomCode && ~isempty(fileNameInfo.customCodeInterfaceHeader)
    ccIntHeaderPath = fileparts(fileNameInfo.customCodeInterfaceHeader);
    includeInfo = [includeInfo {ccIntHeaderPath; 'SLCC_INCLUDES'}];
end

includePathsGroup = [includePathsGroup includeInfo(2,:)];
includePaths = [includePaths includeInfo(1,:)];

assert(length(includePaths) == length(includePathsGroup));

includePathsGroup(cellfun(@isempty,includePaths)) = [];
includePaths(cellfun(@isempty,includePaths)) = [];

if ~isempty(includePaths)
    buildInfo.addIncludePaths(includePaths,includePathsGroup);
end


%Add source files info to buildInfo
numSrcFiles = 0;
for i = 1:length(gMachineInfo.charts)
    for j = 1:length(gMachineInfo.specializations{i})
        if ~gMachineInfo.codingLLVM{i}(j)
            numSrcFiles = numSrcFiles + 1;
        end
    end
end
chartSourceFiles = cell(1, numSrcFiles);

idx = 1;
for i = 1:length(gMachineInfo.charts)
    for j = 1:length(gMachineInfo.specializations{i})
        if ~gMachineInfo.codingLLVM{i}(j)
            chartSourceFiles{idx} = fileNameInfo.chartSourceFiles{i}{j};
            idx = idx + 1;
        end
    end
end

srcFiles=  cell(1,numel(chartSourceFiles) + 1);
srcFilesGroup = cell(size(srcFiles));
srcFiles(1) = {fileNameInfo.machineSourceFile};
srcFilesGroup(1) = {'MODEL_SRC'};
srcFiles(2:end) = chartSourceFiles;
srcFilesGroup(2:end) = {'MODULE_SRCS'};

if ~gTargetInfo.codingLibrary
    srcFiles{end+1} = fileNameInfo.machineRegistryFile;
    srcFilesGroup{end+1} = 'MODEL_REG';
end

for i=1:numel(fileNameInfo.auxInfo.sourceFiles)
    srcFiles{end+1} = fileNameInfo.auxInfo.sourceFiles{i}; %#ok<*AGROW>
    srcFilesGroup{end+1} = 'AUX_SRCS';
end

if ~isempty(compilerSpecificSrc)
    buildInfo.addSourceFiles(compilerSpecificSrc, compilerSpecificPath, 'COMPILER_SRC');
end

buildInfo.addSourceFiles(srcFiles,fileNameInfo.targetDirName,srcFilesGroup);

if gTargetInfo.codingMSVCMakefile || gTargetInfo.codingLccMakefile %Add mexfileapiversion to MSVC and LCC mex files since they do no call
    %mex directly for compiliing
    mexVersionFile =  'c_mexapi_version.c';
    mexVersionPath = fullfile(matlabroot,'extern','version');
    buildInfo.addSourceFiles(mexVersionFile, mexVersionPath, 'COMPILER_SRC');
end

if ~fileNameInfo.hasSLCCCustomCode
    %Get the custom user Sources Information
    for i=1:length(fileNameInfo.userSources)
        [~, ~, extStr] = fileparts(fileNameInfo.userSources{i});
        extStr = lower(extStr);
        if ~(strcmp(extStr, '.c') || strcmp(extStr,'.cpp'))
            error('Stateflow:UnexpectedError',['Unrecognized file extension: ' extStr]);
        end
    end
    buildInfo.addSourceFiles(fileNameInfo.userSources, '','USER_SRCS');
end
%Add source paths to buildInfo
buildInfo.addSourcePaths(fileNameInfo.targetDirName);

%Link BuildInfo options
priority = 100;
precompiled = false;
linkonly  =false;

if (~fileNameInfo.hasSLCCCustomCode && ~isempty(fileNameInfo.userLibraries) )
    %USER_LIBS = \
    for i=1:length(fileNameInfo.userLibraries)
        [libPaths{end+1}, libFiles{end+1}, extLib] = fileparts(fileNameInfo.userLibraries{i});
        libFiles{end} = [libFiles{end} extLib];
        libGroup{end+1} = 'USER_LIBS';
    end
end
numLinkMachines = length(fileNameInfo.linkLibFullPaths);
for i = 1:numLinkMachines
    [libPaths{end+1}, libFiles{end+1}, extLib] = fileparts(fileNameInfo.linkLibFullPaths{i});
    libFiles{end} = [libFiles{end} extLib];
    libGroup{end+1} = 'LINK_MACHINE_LIBS';
    
    %Compute the object list file for the libraries
    [libPaths{end+1}, libFiles{end+1}, extLib] = fileparts(fileNameInfo.linkObjListFullPaths{i});
    libFiles{end} = [libFiles{end} extLib];
    libGroup{end+1} = 'LINK_MACHINE_OBJLIST';
end

%     ...AUX_LNK_OBJS =
for i=1:length(fileNameInfo.auxInfo.linkObjects)
    [libPaths{end+1}, libFiles{end+1}, extLib] = fileparts(fileNameInfo.auxInfo.linkObjects{i});
    libFiles{end} = [libFiles{end} extLib];
    libGroup{end+1} = 'AUX_LNK_OBJS';
end


% sf_runtime lib
[libPaths{end+1}, libFiles{end+1}, extLib] = fileparts(fileNameInfo.sfRuntimeLib);
libFiles{end} = [libFiles{end} extLib];
libGroup{end+1} = 'TMWLIB';

if slfeature('CustomCodeIntegration') && ~gTargetInfo.codingLibrary
    uniqCCDLLs = [fileNameInfo.customCodeDLL fileNameInfo.linkLibCCDLL];
    uniqCCDLLs = uniqCCDLLs(~cellfun(@isempty, uniqCCDLLs));
    uniqCCDLLs = unique(uniqCCDLLs);

    for i = 1:numel(uniqCCDLLs)
        [ccDLLPath, ccDLLFile, ccDLLExt] = fileparts(uniqCCDLLs{i});
        libFiles{end+1} = [ccDLLFile ccDLLExt];
        libPaths{end+1} = ccDLLPath;
        libGroup(end+1) = {'CCLIB'};
    end
end
    
if ispc
    %TMWLIB
    libMexDir = fullfile(matlabroot,'extern','lib',computer('arch'),compilerName);
    libMATLABDir = fullfile(fileNameInfo.matlabRoot,'lib',computer('arch'));

    libFiles(end+1:end+15) = {'libmx.lib','libmex.lib','libmat.lib','libfixedpoint.lib', ...
        'libut.lib', 'libmwstringutil.lib', 'libmwmathutil.lib','libemlrt.lib','libmwsl_log_load_blocks.lib', 'libmwsimulink.lib',...
        'libmwsl_sfcn_cov_bridge.lib', 'libcovrt.lib', 'libmwsl_simtarget_core.lib', 'libmwsl_simtarget_instrumentation.lib', ...
         'libmwslexec_simlog.lib'};
    libPaths(end+1:end+15) = {libMexDir};
    libGroup(end+1:end+15) = {'TMWLIB'};
    if gTargetInfo.codingMinGWMakefile
        libFiles{end+1} = 'libmwipp';
        libPaths{end+1} = fullfile(matlabroot,'bin',computer('arch'));
        libGroup{end+1} = 'TMWLIB';
    else
        libFiles{end+1} = 'libmwipp.lib';
        libPaths{end+1} = libMATLABDir;
        libGroup(end+1) = {'TMWLIB'};
    end
    buildInfo.addLinkObjects(libFiles,libPaths,priority,precompiled,linkonly,libGroup);

elseif isunix
    MLSysLibPath = fullfile(matlabroot,'bin',computer('arch'));
    arch = lower(computer);

    % ...FIXEDPOINTLIB UTLIB EMLRTLIB MWMATHUTILLIB BLASLIB
    libFiles(end+1:end+14) = {'fixedpoint','ut','emlrt','mwstringutil','mwmathutil','mwblas', 'mwsl_log_load_blocks', 'mwsimulink', 'mwsl_sfcn_cov_bridge', ...
		'covrt', 'mwlapack', 'mwsl_simtarget_core', 'mwsl_simtarget_instrumentation', 'mwslexec_simlog'};
    libPaths(end+1:end+14) = {MLSysLibPath};
    libGroup(end+1:end+14) = {'TMWLIB'};

    % ...IPPLIB = -L$matlabroot$/bin/$arch$ -lmwipp
    libFiles{end+1} = 'mwipp';
    libPaths{end+1} = fullfile(matlabroot,'bin',arch);
    libGroup{end+1} = 'TMWLIB';
    if(gTargetInfo.codingOpenMP)
        % ...PARLIB = -L$matlabroot$/sys/os/$arch$ -liomp5
        libFiles{end+1} = 'iomp5';
        libPaths{end+1} = fullfile(matlabroot,'sys','os',arch);
        libGroup{end+1} = 'PARLIB';
    end
    buildInfo.addLinkObjects(libFiles,libPaths,priority,precompiled,linkonly,libGroup);
end

% Add AUX link flags to buildInfo
auxLinkFlags = '';
if ~isempty(fileNameInfo.auxInfo.linkFlags)
    for i = 1:length(fileNameInfo.auxInfo.linkFlags)
        flag = fileNameInfo.auxInfo.linkFlags{i};
        auxLinkFlags = [auxLinkFlags,' ',flag];
    end
end
buildInfo.addLinkFlags(auxLinkFlags,'AUXLDFLAGS');

%Update Build Info with External Dependencies
 %Query third party library information and add it to the buildInfo.
 %The "thirdPartyUses" variable contains classes derived from
 %coder.ExternalDependency and implements the static method updateBuildInfo.
 thirdPartyUses = gMachineInfo.thirdPartyUses; %When inccodegen is enabled
 if ~isempty(thirdPartyUses)
     cs = getActiveConfigSet(gMachineInfo.mainMachineName);
     SLHWImp = getHardwareImplementation(cs);
     tci = getToolChainInfo(buildInfo);
     context = coder.BuildConfig('sfun',SLHWImp,'C', tci, cs, fileNameInfo.targetDirName);

     for itp = 1:numel(thirdPartyUses)
         method = [thirdPartyUses{itp} '.isSupportedContext'];
         if ~feval(method, context)
             method = [thirdPartyUses{itp}  '.getDescriptiveName'];
             construct_coder_error([],sprintf('The library %s is not supported by the current target, language or compiler.',feval(method,context)),1);
         end
         feval([thirdPartyUses{itp} '.updateBuildInfo'],buildInfo,context);
     end
 end

 %Update BuildInfo using the buildInfo method and args provided by
 %coder.updateBuildInfo
 updateBuildInfoArgs = gMachineInfo.updateBuildInfoArgs; %When inccodegen is enabled
 if ~isempty(updateBuildInfoArgs)         
     for i  = 1:numel(updateBuildInfoArgs)
         methodName = updateBuildInfoArgs{i}{1};
         methodArgs = updateBuildInfoArgs{i}{2};
         feval(methodName,buildInfo,methodArgs{:});
     end
 end
     
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function tci = getToolChainInfo(buildInfo)
global gTargetInfo
tci = [];
try
    tci = buildInfo.getBuildToolInfo('ToolchainInfo');
catch
end
if isempty(tci)
    %Synthesize a ToolchainInfo
    tci = coder.make.ToolchainInfo();
    try
        compilerInfo = sfprivate('compilerman','get_compiler_info', gTargetInfo.gencpp);
        tci.Name = compilerInfo.compilerFullName;
    catch
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function hwi = getHardwareImplementation(cs)
%Synthesize a Hardware Implementation.
hw_model = cs.getComponent('Hardware Implementation');
hwi = hw_model.copy();
if ~hwi.getPropEnabled('ProdHWDeviceType')
    hwi.setPropEnabled('ProdHWDeviceType',true);
end
hwi.ProdHWDeviceType = 'Generic->MATLAB Host Computer';     
