function fileNameInfo = create_file_name_info()
% FILENAMEINFO = CREATE_FILE_NAME_INFO

% Copyright 1995-2019 The MathWorks, Inc.
%

global gMachineInfo gTargetInfo %#ok<GVMIS>

% root directory determination: get the model of the parentTarget
% get the filename property of the model which will give you
% model directory. this dir will be used for constructing abs path
% from relative paths in user source files, user incl dirs etc.

parentTargetMachine = sf('get',gMachineInfo.parentTarget,'target.machine');
modelH = sf('get',parentTargetMachine,'machine.simulinkModel');
currentDirPath = pwd;

[projectDirPath,projectDirArray, projectDirRelPath, projectDirReverseRelPath] = sfprivate('get_sf_proj',pwd,gMachineInfo.mainMachineName,gMachineInfo.machineName,gMachineInfo.targetName,'src');
fileNameInfo.targetDirName = projectDirPath;
fileNameInfo.targetDirRelPath = projectDirRelPath;
baseName = [gMachineInfo.machineName,'_',gMachineInfo.targetName];
if gTargetInfo.codingRTW || gTargetInfo.codingSFunction
fileNameInfo.mexFunctionName = baseName;
fileNameInfo.dllDirFromMakeDir = projectDirReverseRelPath;
fileNameInfo.projectDirArray = projectDirArray;
% Coding GPU does not using JIT, and need pre-mkdir
if ~gTargetInfo.codingGPU
% we will call create_directory_path just in time rather than here
% this is needed for the LLVM-JIT mode where we do not want to pollute the current dir
else
create_project_dir_path_just_in_time(fileNameInfo);
end
elseif gTargetInfo.codingMEX || gTargetInfo.codingHDL
fileNameInfo.targetDirName = pwd;
fileNameInfo.dllDirFromMakeDir = '.\';
else
codegenDir = sf('get',gMachineInfo.parentTarget,'target.codegenDirectory');

if(isempty(codegenDir))
fileNameInfo.targetDirName = projectDirPath;
[dirName, success, errorCreateMsg] = sfprivate('create_directory_path',projectDirArray{:});
if(~success)
construct_dir_path_error(dirName,errorCreateMsg);
end
fileNameInfo.dllDirFromMakeDir = projectDirReverseRelPath;
else
codegenDirOrig = codegenDir;
[codegenDir,errorStrs] = CGXE.Utils.tokenize(currentDirPath,codegenDir,getString(message('Stateflow:sfprivate:CodeGenerationDirectoryString')));
if ~isempty(errorStrs)
for ii=1:numel(errorStrs)
errorStr = errorStrs{ii};
if(errorStr.TreatDiagAsError)
construct_coder_error(gMachineInfo.parentTarget,errorStr.Msg);
else
sfprivate('construct_warning', gMachineInfo.parentTarget, 'Coder', errorStr.Msg, '');
end
end
end

codegenDir = codegenDir{1};

if(~isfolder(codegenDir))
[success, errorMessage] = sfprivate('sf_mk_dir', currentDirPath, codegenDirOrig);

if(~success)
construct_dir_path_error(codegenDir, errorMessage);
end
end

fileNameInfo.targetDirName = codegenDir;
fileNameInfo.dllDirFromMakeDir = '.\';
end
end
if(sfprivate('testing_stateflow_in_bat'))
% make sure we are generating code in
% MATLAB directories
if(contains(lower(fileNameInfo.targetDirName),lower(matlabroot)))
construct_coder_error([],'Code generation in MATLAB directories during Stateflow testing is prohibited.',1);
end
end

% Can't generate C++ s-function using lcc
if gTargetInfo.codingSFunction && isempty(gTargetInfo.compilerName)
errorId = 'Simulink:cgxe:MexCompilerNotFound';
sfprivate('construct_error', gMachineInfo.parentTarget, 'Coder', ...
getString(message(errorId)), true, errorId);
end

if gTargetInfo.codingRTW
fileNameInfo.headerExtension = '.tlh';
fileNameInfo.sourceExtension = '.tlc';
elseif gTargetInfo.codingHDL
fileNameInfo.headerExtension = '';
fileNameInfo.sourceExtension = '';
elseif gTargetInfo.codingPLC
fileNameInfo.headerExtension = ''; % no header file
fileNameInfo.sourceExtension = gTargetInfo.plc.fileExt;
else
fileNameInfo.headerExtension = '.h';
if gTargetInfo.codingGPU
fileNameInfo.sourceExtension = '.cu';
elseif gTargetInfo.gencpp
fileNameInfo.sourceExtension = '.cpp';
else
fileNameInfo.sourceExtension = '.c';
end
end
if(gTargetInfo.codingSFunction)
fileNameInfo.machineRegistryFile = [baseName,'_registry',fileNameInfo.sourceExtension];
end

fileNameInfo.machineHeaderFile = [baseName,fileNameInfo.headerExtension];
fileNameInfo.machineSourceFile = [baseName,fileNameInfo.sourceExtension];

numCharts = length(gMachineInfo.charts);
fileNameInfo.chartHeaderFiles = cell(1,numCharts);
fileNameInfo.chartSourceFiles = cell(1,numCharts);
fileNameInfo.chartSpecUniqueNames = cell(1,numCharts);
fileNameInfo.chartTLCFiles = cell(1,numCharts);
fileNameInfo.chartOutputsFcns = cell(1,numCharts);
fileNameInfo.chartInitializeFcns = cell(1,numCharts);

if gTargetInfo.codingRTW
machineSourceFile = fileNameInfo.machineSourceFile;
sf('set',gMachineInfo.machineId,'machine.rtwInfo.machineTLCFile',machineSourceFile(1:end-length(fileNameInfo.sourceExtension)));
end

for chart = gMachineInfo.charts
chartNumber = sf('get',chart,'chart.number');

%TLTODO: Handle all targets
numSpecs = length(gMachineInfo.specializations{chartNumber+1});
for j = 1:numSpecs
chartSpecUniqueName = sf('CodegenNameOf', chart, gMachineInfo.specializations{chartNumber+1}{j});
if(gTargetInfo.codingDllTargetForSLTest)
if(Stateflow.STT.Utils.ScenarioCodegenHelper.chart_has_scenarios(chart))
% override for dlltarget for scenarios
activeScenarioState = Stateflow.STT.Utils.ScenarioCodegenHelper.get_active_scenario_state(chart);
if(isscalar(activeScenarioState))
scenarioName = sf('get',activeScenarioState,'.name');
chartSpecUniqueName = scenarioName;
end
end
end
fileNameInfo.chartSpecUniqueNames{chartNumber+1}{j} = chartSpecUniqueName;

if gTargetInfo.codingSFunction || gTargetInfo.codingRTW
fileNameInfo.chartHeaderFiles{chartNumber+1}{j} = [chartSpecUniqueName,fileNameInfo.headerExtension];
fileNameInfo.chartSourceFiles{chartNumber+1}{j} = [chartSpecUniqueName,fileNameInfo.sourceExtension];
fileName = fullfile(fileNameInfo.targetDirName,fileNameInfo.chartSourceFiles{chartNumber+1}{j});

% Windows paths are limited to 260 characters. Let's add an extra
% 20-character margin because of interface and support files that
% have longer names.
if (ispc && length(fileName) >= 240)
sfprivate('construct_error', chart, 'Build', DAStudio.message('Stateflow:sfprivate:LongPathErrorWindows', fileName), 1);
return;
end
else
fileNameInfo.chartHeaderFiles{chartNumber+1} = [chartSpecUniqueName,fileNameInfo.headerExtension];
fileNameInfo.chartSourceFiles{chartNumber+1} = [chartSpecUniqueName,fileNameInfo.sourceExtension];
end

% chartTLCFile, chartOutputsFcn, chartInitializeFcn are only used when coder unification is turned off
if(gTargetInfo.codingRTW)
fileNameInfo.chartTLCFiles{chartNumber+1}{j} = chartSpecUniqueName;
fileNameInfo.chartOutputsFcns{chartNumber+1}{j} = ['sf_',chartSpecUniqueName];
end

if gTargetInfo.codingRTW || gTargetInfo.codingMEX
fileNameInfo.chartInitializeFcns{chartNumber+1}{j} = ['initialize_',chartSpecUniqueName];
end
end
end

if(gTargetInfo.codingDllTargetForSLTest)
fileNameInfo.interfaceSourceFileName = 'SLTestSequenceDllInterface.cpp';
fileNameInfo.interfaceHeaderFileName = 'SLTestSequenceDllInterface.h';
end

compilerInfo = gTargetInfo.compilerInfo;

fileNameInfo.mexSetEnv = compilerInfo.mexSetEnv;

fileNameInfo.matlabRoot = matlabroot;
fileNameInfo.stddefIncludeFile = [];
fileNameInfo.openMPIncludeFile = [];
fileNameInfo.isOverflowLoggingEnabled = false;

if(gTargetInfo.codingSFunction)
fileNameInfo.makeBatchFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.bat'];
fileNameInfo.machineDefFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.def'];
fileNameInfo.SFunctionName = [gMachineInfo.machineName,'_',gMachineInfo.targetName];
fileNameInfo.unixMakeFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.mku'];
fileNameInfo.msvcdspFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.dsp'];
fileNameInfo.msvcdswFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.dsw'];
fileNameInfo.msvcvcprojFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.vcproj'];
fileNameInfo.msvcMakeFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.mak'];
fileNameInfo.lccMakeFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.lmk'];
fileNameInfo.objListFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.mol'];
fileNameInfo.mingwMakeFile = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.gmk'];

fileNameInfo.isOverflowLoggingEnabled = ...
sfprivate('checkNeedAmsiTable',gMachineInfo.mainMachineId,gMachineInfo.mainMachineName,'sfun',true);
end
if(gTargetInfo.codingDllTargetForSLTest)
[~,moduleName] = fileparts(fileNameInfo.chartSourceFiles{1});
fileNameInfo.makeBatchFile = [moduleName,'.bat'];
fileNameInfo.moduleName = moduleName;
if(ispc && ~gTargetInfo.codingSLRT)
fileNameInfo.dllFileName = [moduleName,'.dll'];
else
fileNameInfo.dllFileName = [moduleName,'.so'];
if(isunix)
fileNameInfo.unixShellScript = [gMachineInfo.machineName,'_',gMachineInfo.targetName,'.sh'];
end
end
end
if (~gTargetInfo.codingRTW)
fileNameInfo.rtwHeadersInclude = fullfile(fileNameInfo.matlabRoot,'stateflow','c','mex','include');
fileNameInfo.archName = computer('arch');
if gTargetInfo.codingOpenMP
fileNameInfo.openMPIncludeFile = 'omp.h';
end
end

fileNameInfo.sfRuntimeIncludeDir = fullfile(fileNameInfo.matlabRoot, 'simulink', 'include');
if(ispc)
fileNameInfo.sfRuntimeLib = constructWindowsLibraryPath(compilerInfo, fileNameInfo, 'sf_runtime.lib');
else
fileNameInfo.sfRuntimeLibDir = '';
fileNameInfo.sfRuntimeLib = fullfile(fileNameInfo.matlabRoot,'bin',computer('arch'),'mwsf_runtime');
end

% Legacy interface function
modelName = get_param(modelH, 'name');

extraIncludes = {};

if gTargetInfo.codingRTW || gTargetInfo.codingSFunction || gTargetInfo.codingCustom
customCodeSettings = get_custom_code_settings(gMachineInfo.target,gMachineInfo.parentTarget);

[fileNameInfo, errorStrs] = customCodeSettings.addToFileNameInfo(fileNameInfo, modelName, extraIncludes, gTargetInfo.codingSFunction);
if ~isempty(errorStrs)
for ii=1:numel(errorStrs)
errorStr = errorStrs{ii};
if(errorStr.TreatDiagAsError)
construct_coder_error(customCodeSettings.relevantTargetId,errorStr.Msg);
else
sfprivate('construct_warning', customCodeSettings.relevantTargetId, 'Coder', errorStr.Msg, '');
end
end
end
fileNameInfo = fix_user_path_for_make_file(fileNameInfo);
end

if gTargetInfo.codingSFunction
fileNameInfo.customUserDefines = getFixedCustomDefines(customCodeSettings.customUserDefines, compilerInfo);

fileNameInfo.hasSLCCCustomCode = false;
fileNameInfo.customCodeChecksum = '';
fileNameInfo.customCodeDLL = '';
fileNameInfo.customCodeInterfaceHeader = '';

isEditTime = strcmpi(get_param(modelH, 'SimulationStatus'), 'stopped');
if ~isEditTime
relevantMachineId = sf('get', customCodeSettings.relevantTargetId, 'target.machine');
relevantMachineName = sf('get',relevantMachineId,'machine.name');
relevantMachineHandle = get_param(relevantMachineName,'Handle');

ccCheckSum = slcc('getModelCustomCodeChecksum', relevantMachineHandle, false); % false: check existence of SLCC custom code without requiring SimDLL
fileNameInfo.hasSLCCCustomCode = ~isempty(ccCheckSum); % Has SLCC opt-in custom code

[ccCheckSum, isOOP] = slcc('getModelCustomCodeChecksum', relevantMachineHandle);
if ~isempty(ccCheckSum)
fileNameInfo.customCodeChecksum = ccCheckSum;
if ~isOOP
fileNameInfo.customCodeDLL = CGXE.CustomCode.getCustomLibNameFromModel(relevantMachineName,'import', ccCheckSum);
ccDllDirPath = fileparts(fileNameInfo.customCodeDLL);
fileNameInfo.customCodeInterfaceHeader = fullfile(ccDllDirPath, ['slcc_interface_' ccCheckSum '.h']);
else
fileNameInfo.customCodeDLL = "";
fullChecksum = slcc('getCustomCodeFullChecksum', relevantMachineHandle);
expectedExeFullPath = SLCC.OOP.getCustomCodeExeExpectedFullPath(ccCheckSum, fullChecksum);
ccExeDirPath = fileparts(expectedExeFullPath);
fileNameInfo.customCodeInterfaceHeader = fullfile(ccExeDirPath, [ccCheckSum, '_interface.h']);
end
end
end
end

fileNameInfo.linkMachines = {};
fileNameInfo.linkLibFullPaths = {};
fileNameInfo.linkObjListFullPaths = {};
fileNameInfo.linkMachinesInlinable = {};
if(~gTargetInfo.codingLibrary)
[fileNameInfo.linkMachines,fileNameInfo.linkLibFullPaths, ~, fileNameInfo.linkObjListFullPaths, ...
fileNameInfo.linkLibCCDLL] = sfprivate('get_link_machine_list',gMachineInfo.machineName,gMachineInfo.targetName);
for i=1:length(fileNameInfo.linkMachines)
infoStruct = sfprivate('infomatman','load','binary',fileNameInfo.linkMachines{i},gMachineInfo.mainMachineId,gMachineInfo.targetName);
fileNameInfo.linkMachinesInlinable{i} = infoStruct.machineInlinable;
end
end

% Attach fileNameInfo to gTargetInfo for Deep Learning
if gTargetInfo.gencpp
gTargetInfo.fileNameInfo = fileNameInfo;
end

function customDefines = getFixedCustomDefines(customDefines, compilerInfo)
customDefines = strtrim(customDefines);
if isempty(customDefines)
return;
end
if ismember(compilerInfo.compilerName, cgxeprivate('supportedPCCompilers','microsoft'))
defineToken = '/D';
else
defineToken = '-D';
end
%Split the defines, add the'D" flag and re-join
defineList = CGXE.CustomCode.extractUserDefines(customDefines);
customDefines = strjoin(strcat(defineToken, defineList),' ');

function compilerFolderName = getWindowsCompilerFolderName(compilerInfo)
compilerFolderName = compilerInfo.compilerName;
if ~isempty(regexp(compilerFolderName, '^msvc|^mssdk', 'once'))
compilerFolderName = 'microsoft';
elseif strcmp(computer,'PCWIN64') && strcmp(compilerFolderName,'lcc')
% On Windows64, LCC compiler can read Visual Studio DLL symbols.
compilerFolderName = 'microsoft';
elseif ~isempty(regexp(compilerFolderName, '^mingw64', 'once'))
compilerFolderName = 'mingw64';
end

function libPath = constructWindowsLibraryPath(compilerInfo, fileNameInfo, libName)

compilerFolderName = getWindowsCompilerFolderName(compilerInfo);
libPath = fullfile(fileNameInfo.matlabRoot,'extern','lib',computer('arch'),compilerFolderName,libName);

function fileNameInfo = fix_user_path_for_make_file(fileNameInfo)

fileNameInfo.userIncludeDirs = CGXE.Utils.fix_windows_paths_for_make_file(fileNameInfo.userIncludeDirs);
fileNameInfo.userSources = CGXE.Utils.fix_windows_paths_for_make_file(fileNameInfo.userSources);
fileNameInfo.userLibraries = CGXE.Utils.fix_windows_paths_for_make_file(fileNameInfo.userLibraries);
fileNameInfo.userMakefiles = CGXE.Utils.fix_windows_paths_for_make_file(fileNameInfo.userMakefiles);
fileNameInfo.userAbsSources = CGXE.Utils.fix_windows_paths_for_make_file(fileNameInfo.userAbsSources);
fileNameInfo.userAbsPaths = CGXE.Utils.fix_windows_paths_for_make_file(fileNameInfo.userAbsPaths);