function code_unix_make_file(fileNameInfo,buildInfo,modelName)
% CODE_UNIX_MAKE_FILE(FILENAMEINFO)

% Copyright 1995-2023 The MathWorks, Inc.
%

global gMachineInfo gTargetInfo %#ok<GVMIS>
ext = '.o';
code_machine_objlist_file(fileNameInfo, buildInfo, ext);

fileName = fullfile(fileNameInfo.targetDirName,fileNameInfo.unixMakeFile);
sf_echo_generating('Coder',fileName);
file = fopen(fileName,'Wt');
if file<3
construct_coder_error([],getString(message('Stateflow:sfprivate:error_FailedToCreateFile',fileName)),1);
end

DOLLAR = '$';
fprintf(file,'#--------------------------- Tool Specifications -------------------------\n');
fprintf(file,'#\n');
fprintf(file,'# Modify the following macros to reflect the tools you wish to use for\n');
fprintf(file,'# compiling and linking your code.\n');
fprintf(file,'#\n');
if(~isempty(fileNameInfo.userMakefiles))
for i=1:length(fileNameInfo.userMakefiles)
fprintf(file,'include $fileNameInfo.userMakefiles{i}\n');
end
end
mexCFlag = '-R2018a';
if(gTargetInfo.codingMakeDebug)
fprintf(file,'CC = %s/bin/mex %s -g\n',matlabroot,mexCFlag);
else
fprintf(file,'CC = %s/bin/mex %s\n',matlabroot,mexCFlag);
end
fprintf(file,'LD = %s(CC)\n',DOLLAR);
if gTargetInfo.codingGPU
fprintf(file,'NVCC = nvcc\n');
end
fprintf(file,' \n');
fprintf(file,'MODEL = %s\n',gMachineInfo.machineName);
fprintf(file,'TARGET = %s\n',gMachineInfo.targetName);

moduleSrcs = getCatString(buildInfo.getSourceFiles(false,true,'MODULE_SRCS'));
fprintf(file,'MODULE_SRCS = %s\n',moduleSrcs);

modelSrc = getCatString(buildInfo.getSourceFiles(false,true,'MODEL_SRC'));
fprintf(file,'MODEL_SRC = %s\n',modelSrc);
modelReg = getCatString(buildInfo.getSourceFiles(false,true,'MODEL_REG'));
fprintf(file,'MODEL_REG = %s\n',modelReg);

fprintf(file,'MAKEFILE = %s\n',fileNameInfo.unixMakeFile);

fprintf(file,'MATLAB_ROOT = %s\n',fullfile(sf('Root'),'..','..','..'));
fprintf(file,'BUILDARGS = \n');

%
% g2680582: this fix allows the use of $(START_DIR) to represent the local anchor directory
% where source (or header) file directories may reside when using coder.updateBuildInfo
% (path expansion methods use this setting to expand the START_DIR macro)
%
if gTargetInfo.codingSFunction
buildInfo.Settings.LocalAnchorDir = fileNameInfo.projectDirArray{1};
end

fprintf(file,'#------------------------------ Include/Lib Path ------------------------------\n');
fprintf(file,' \n');
userIncludeDirString = '';
userIncludeDirs = buildInfo.getIncludePaths(true,'USER_INCLUDES');
if ~isempty(userIncludeDirs)
for i = 1:length(userIncludeDirs)
userIncludeDirString = [userIncludeDirString,'-I"',userIncludeDirs{i},'" ']; %#ok<AGROW>
end
end
fprintf(file,'USER_INCLUDES = %s\n',userIncludeDirString);

auxIncludeDirString = '';
auxincludePaths = buildInfo.getIncludePaths(true,'AUX_INCLUDES');
if ~isempty(auxincludePaths)
for i = 1:length(auxincludePaths)
path = auxincludePaths{i};
auxIncludeDirString = [auxIncludeDirString,'-I"',path,'" ']; %#ok<AGROW>
end
end

fprintf(file,'AUX_INCLUDES = %s\n',auxIncludeDirString);
% All file Inlcudes
mlslsfInclude = buildInfo.getIncludePaths(true,{'ML_INCLUDES','SL_INCLUDES','SF_INCLUDES'});
fprintf(file,'MLSLSF_INCLUDES = \\\n');
% Add CUDA headers shipped with MATLAB
if gTargetInfo.codingGPU
gpucoderCudaUtilInclude = '$(MATLAB_ROOT)/toolbox/shared/gpucoder/src/cuda/export/include/cuda';
gpucoderThrustUtilInclude = '$(MATLAB_ROOT)/toolbox/gpucoder/gpucoder/src/cuda/thrust';
cudaInclude = '$(MATLAB_ROOT)/sys/cuda/glnxa64/cuda/include';
fprintf(file,' -I"%s" \\\n',cudaInclude);
fprintf(file,' -I"%s" \\\n',gpucoderCudaUtilInclude);
fprintf(file,' -I"%s" \\\n',gpucoderThrustUtilInclude);
end
for i = 1:numel(mlslsfInclude) -1
fprintf(file,' -I"%s" \\\n',mlslsfInclude{i});
end
fprintf(file,' -I"%s" \n',mlslsfInclude{end});
fprintf(file,'\n');
thirdPartyIncludes = buildInfo.getIncludePaths(true,{},{'USER_INCLUDES','AUX_INCLUDES',...
'ML_INCLUDES','SL_INCLUDES','SF_INCLUDES'});

thirdPartyIncludesString = '';
for i = 1:length(thirdPartyIncludes)
if coder.make.internal.isRelativePath(thirdPartyIncludes{i})
thirdPartyIncludes{i} = [fileNameInfo.projectDirArray{1}, filesep, thirdPartyIncludes{i}];
end
thirdPartyIncludesString = [thirdPartyIncludesString,'-I"',thirdPartyIncludes{i},'" ']; %#ok<AGROW>
end
fprintf(file,'THIRD_PARTY_INCLUDES = %s\n',thirdPartyIncludesString);
fprintf(file,'\n');
fprintf(file,'INCLUDE_PATH = %s(USER_INCLUDES) %s(AUX_INCLUDES) %s(MLSLSF_INCLUDES) %s(COMPILER_INCLUDES) %s(THIRD_PARTY_INCLUDES)\n',DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR);
fprintf(file,' \n');

fprintf(file,'#----------------- Compiler and Linker Options --------------------------------\n');
fprintf(file,' \n');
fprintf(file,'# Optimization Options\n');

fprintf(file,' \n');
fprintf(file,'CC_OPTS = %s %s\n',getCatString(buildInfo.getCompileFlags),getCatString(buildInfo.getDefines));

fprintf(file,'CPP_REQ_DEFINES = -DMATLAB_MEX_FILE\n');
fprintf(file,' \n');
fprintf(file,'# Uncomment this line to move warning level to W4\n');
fprintf(file,'# cflags = %s(cflags:W3=W4)\n',DOLLAR);
fprintf(file,'CFLAGS = %s(CPP_REQ_DEFINES) %s(INCLUDE_PATH) CFLAGS="\\%s%sCFLAGS %s(CC_OPTS)"\n',DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR);
if gTargetInfo.codingGPU
if ~isempty(gTargetInfo.gpuCustomComputeCapability)
gpuFlags = gTargetInfo.gpuCustomComputeCapability;
ptxVersion = '500';
else
ccVals = regexp(gTargetInfo.gpuComputeCapability,'\.','split');
gpuFlags = ['-arch sm_' ccVals{1} ccVals{2}];
ptxVersion = [ccVals{1} ccVals{2} '0'];
end
gpuFlags = [gpuFlags ' -DMW_CUDA_ARCH=' ptxVersion];
if ~isempty(gTargetInfo.gpuCompilerFlags)
gpuFlags = [gpuFlags ' ' gTargetInfo.gpuCompilerFlags];
end

fprintf(file,'CUFLAGS_NO_RDC = %s(CPP_REQ_DEFINES) %s(INCLUDE_PATH) %s(CC_OPTS) %s -Xcompiler -fPIC,-fno-gnu-unique -noprof -ldir "%s(MATLAB_ROOT)/bin/glnxa64" -I "%s(MATLAB_ROOT)/sys/cuda/glnxa64/cuda/include"\n',DOLLAR,DOLLAR,DOLLAR,gpuFlags,DOLLAR,DOLLAR);
fprintf(file,'CUFLAGS = %s(CUFLAGS_NO_RDC) -rdc=true\n',DOLLAR);
end
fprintf(file,' \n');
fprintf(file,'LDFLAGS = %s\n',getCatString(buildInfo.getLinkFlags));
fprintf(file,'LINKLIBS = %s\n',getCatString(buildInfo.getLinkFlags('LINKLIBS')));
fprintf(file,' \n');
fprintf(file,'AUXLDFLAGS = %s\n',getCatString(buildInfo.getLinkFlags('AUXLDFLAGS')));

fprintf(file,'#----------------------------- Source Files -----------------------------------\n');
fprintf(file,' \n');
fprintf(file,'REQ_SRCS = %s(MODEL_SRC) %s(MODEL_REG) %s(MODULE_SRCS)\n',DOLLAR,DOLLAR,DOLLAR);
fprintf(file,'\n');
userSources = buildInfo.getSourceFiles(true,true,'USER_SRCS');

if(~isempty(userSources))
fprintf(file,'USER_OBJS = \\\n');
for i=1:length(userSources)
[~, nameStr] = fileparts(userSources{i});
objStr = [nameStr '.o'];
fprintf(file,' %s \\\n',objStr);
end
else
fprintf(file,'USER_OBJS =\n');
end
fprintf(file,'\n');
auxSources = buildInfo.getSourceFiles(true,true,'AUX_SRCS');
if ~isempty(auxSources)
fprintf(file,'AUX_ABS_OBJS = \\\n');
for i=1:numel(auxSources)
[~, nameStr] = fileparts(auxSources{i});
objStr = [nameStr '.o'];
fprintf(file,' %s \\\n',objStr);
end
fprintf(file,'\n');
else
fprintf(file,'AUX_ABS_OBJS =\n');
end

thirdPartyExcludeGroups = {'MODULE_SRCS','MODEL_SRC','MODEL_REG','USER_SRCS','AUX_SRCS'};
thirdPartySources = buildInfo.getSourceFiles(true,true,{}, thirdPartyExcludeGroups);
% Third Party Source Paths contain only paths specfied in
% coder.ExternalDepedency or coder.Buildable
thirdPartySourcePaths = buildInfo.getSourcePaths(true);

%
% g2680582: this fix cleans the use of the local anchor dir as it was not originally set
% from with the gTargetInfo
%
if gTargetInfo.codingSFunction
buildInfo.Settings.LocalAnchorDir = '';
end
if(~isempty(thirdPartySources))
fprintf(file,'THIRD_PARTY_OBJS = \\\n');
for i=1:length(thirdPartySources)
[~, nameStr] = fileparts(thirdPartySources{i});
objStr = [nameStr '.o'];
fprintf(file,' %s \\\n',objStr);
end
else
fprintf(file,'THIRD_PARTY_OBJS =\n');
end
fprintf(file,'\n');

fprintf(file,'REQ_OBJS = %s(REQ_SRCS:.cpp=.o)\n',DOLLAR);
fprintf(file,'REQ_OBJS2 = %s(REQ_OBJS:.c=.o)\n',DOLLAR);
if gTargetInfo.codingGPU
fprintf(file,'REQ_OBJS3 = %s(REQ_OBJS2:.cu=.o)\n',DOLLAR);
fprintf(file,'OBJS = %s(REQ_OBJS3) %s(USER_OBJS) %s(AUX_ABS_OBJS) %s(THIRD_PARTY_OBJS)\n',DOLLAR,DOLLAR,DOLLAR,DOLLAR);
else
fprintf(file,'OBJS = %s(REQ_OBJS2) %s(USER_OBJS) %s(AUX_ABS_OBJS) %s(THIRD_PARTY_OBJS)\n',DOLLAR,DOLLAR,DOLLAR,DOLLAR);
end
fprintf(file,'OBJLIST_FILE = %s\n',fileNameInfo.objListFile);

arch = lower(computer);

fprintf(file,'SFCLIB = %s\n',getLinkObjStringForGroup(buildInfo,'SFCLIB'));

fprintf(file,'AUX_LNK_OBJS = %s\n',getLinkObjStringForGroup(buildInfo,'AUX_LNK_OBJS'));
fprintf(file,'USER_LIBS = %s\n',getLinkObjStringForGroup(buildInfo,'USER_LIBS'));

fprintf(file,'PARLIB = %s\n',getLinkObjStringForGroup(buildInfo,'PARLIB'));

if gTargetInfo.codingGPU
shippingCudaLibs = coder.gpu.internal.getLinuxShippingCudaLibs();
cudaLib = ['-I"$(MATLAB_ROOT)/sys/cuda/glnxa64/cuda/include" -L"$(MATLAB_ROOT)/sys/cuda/glnxa64/cuda/lib64" -L"$(MATLAB_ROOT)/bin/glnxa64" ', strjoin([{''}, shippingCudaLibs], ' -l')];
fprintf(file,'CUDALIB = %s\n',cudaLib);
gpucoderCudaUtilLib = '$(MATLAB_ROOT)/bin/glnxa64/libmwgpucoder_cuda.a';
fprintf(file,'GPUCODER_CUDA_UTIL_LIB = "%s"\n',gpucoderCudaUtilLib);
end

fprintf(file,' MAPCSF = %s/tools/%s/mapcsf\n',matlabroot,arch);
fprintf(file,' # RUN_MAPCSF_ON_UNIX is defined only if MAPCSF exists on this platform.\n');
fprintf(file,' ifneq (%s(wildcard %s(MAPCSF)),) # run MAPCSF if it exists on this platform\n',DOLLAR,DOLLAR);
fprintf(file,' RUN_MAPCSF_ON_UNIX = %s/tools/%s/mapcsf %s@\n',matlabroot,arch,DOLLAR);
fprintf(file,' endif\n');

excludeGroups = {'SFCLIB','USER_LIBS','LINK_MACHINE_LIBS', ...
'LINK_MACHINE_OBJLIST','TMWLIB','PARLIB'};

userGroups = {};
if gTargetInfo.codingLibrary
libObjListfile = ['lib_' fileNameInfo.objListFile];
CGXE.Coder.code_append_user_external_link_flags_for_library(libObjListfile, fileNameInfo.targetDirName, buildInfo);
else
libObjListfile = fileNameInfo.objListFile;
end
libList = {};
libListTmp0 = code_append_libs_to_objlist_file_unix(libObjListfile, ...
fileNameInfo.targetDirName, buildInfo,userGroups,excludeGroups);
libListTmp1 = CGXE.Coder.code_append_syslibs_to_objlist_file(libObjListfile,fileNameInfo.targetDirName, ...
buildInfo, modelName); %Third Party Libraries
libList = [libList(:)', libListTmp0(:)', libListTmp1(:)'];
fprintf(file,' \n');
fprintf(file,'#--------------------------------- Rules --------------------------------------\n');
fprintf(file,' \n');
if gTargetInfo.codingLibrary

if ismac
fprintf(file,'DO_RANLIB = xcrun ranlib %s(MODEL)_%s(TARGET).a\n',DOLLAR,DOLLAR);
else
fprintf(file,'DO_RANLIB = ranlib %s(MODEL)_%s(TARGET).a\n',DOLLAR,DOLLAR);
end
fprintf(file,' \n');
fprintf(file,'%s(MODEL)_%s(TARGET).a : %s(MAKEFILE) %s(OBJS) %s(SFCLIB) %s(AUX_LNK_OBJS) %s(USER_LIBS) %s(THIRD_PARTY_LIBS)\n',DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR);
fprintf(file,' @echo ### Linking ...\n');
if ismac
fprintf(file,' xcrun ar ruv %s(MODEL)_%s(TARGET).a %s(OBJS)\n',DOLLAR,DOLLAR,DOLLAR);
else
fprintf(file,' ar ruv %s(MODEL)_%s(TARGET).a %s(OBJS)\n',DOLLAR,DOLLAR,DOLLAR);
end
fprintf(file,' %s(DO_RANLIB)\n',DOLLAR);
else
% Due to g1205457 added the list of libs to the objlist file only for the MEX file
% we do not want to archive libraries into intermediate static libraries
libListTmp0 = code_append_libs_to_objlist_file_unix(libObjListfile, ...
fileNameInfo.targetDirName, buildInfo, 'LINK_MACHINE_LIBS');
libListTmp1 =code_append_libs_to_objlist_file_unix(libObjListfile, ...
fileNameInfo.targetDirName, buildInfo, 'TMWLIB');
libListTmp2 =code_append_libs_to_objlist_file_unix(libObjListfile,...
fileNameInfo.targetDirName, buildInfo, 'LINK_MACHINE_OBJLIST');
libList = [libList(:)', libListTmp0(:)', libListTmp1(:)', libListTmp2(:)'];
if(gTargetInfo.codingMEX && ~isempty(sf('get',gMachineInfo.target,'target.mexFileName')))
fprintf(file,'MEX_FILE_NAME = %s.%s\n',sf('get',gMachineInfo.target,'target.mexFileName'),mexext);
else
fprintf(file,'MEX_FILE_NAME = %s(MODEL)_%s(TARGET).%s\n',DOLLAR,DOLLAR,mexext);
end
fprintf(file,' \n');
if gTargetInfo.codingGPU
systemLibStr = [];
for i = 1:numel(libList)
systemLibStr = [systemLibStr, ' ', libList{i}]; %#ok<AGROW>
end
% Replace newline with space
systemLibStr = strrep(systemLibStr, newline, ' ');
fprintf(file,' SYSLIB = %s\n',systemLibStr);
fprintf(file,'\n');
end

fprintf(file,' %s(MEX_FILE_NAME): %s(MAKEFILE) %s(OBJS) %s(SFCLIB) %s(AUX_LNK_OBJS) %s(USER_LIBS)\n',DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR);
fprintf(file,' @echo ### Linking ...\n');
if gTargetInfo.codingGPU
fprintf(file,' %s(NVCC) -shared -o %s(MEX_FILE_NAME) %s(OBJS) %s(AUX_LNK_OBJS) %s(USER_LIBS) %s(SFCLIB) %s(PARLIB) %s(IPPLIB) %s(THIRD_PARTY_LIBS) %s(SYSLIB) %s(CUDALIB) %s(GPUCODER_CUDA_UTIL_LIB) %s(LDFLAGS) %s\n',DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,gpuFlags);
else
fprintf(file,' %s(CC) -silent LDFLAGS="\\%s%sLDFLAGS %s(LDFLAGS)" LINKLIBS="\\%s%sLINKLIBS %s(AUXLDFLAGS)" -output %s(MEX_FILE_NAME) @%s(OBJLIST_FILE) %s(AUX_LNK_OBJS) %s(USER_LIBS) %s(SFCLIB) %s(PARLIB) %s(IPPLIB) %s(THIRD_PARTY_LIBS)\n',DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR,DOLLAR);
end
fprintf(file,' %s(RUN_MAPCSF_ON_UNIX)\n',DOLLAR);
fprintf(file,'\n');
end

%Use nvcc to compile all source files to avoid the complications of passing flags to host compiler and nvcc.
if gTargetInfo.codingGPU
fprintf(file,'%%.o : %%.c\n');
fprintf(file,' %s(NVCC) -c %s(CUFLAGS) %s<\n',DOLLAR,DOLLAR,DOLLAR);
fprintf(file,'\n');
fprintf(file,'%%.o : %%.cpp\n');
fprintf(file,' %s(NVCC) -c %s(CUFLAGS) %s<\n',DOLLAR,DOLLAR,DOLLAR);
fprintf(file,'\n');
fprintf(file,'%%.o : %%.cu\n');
fprintf(file,' %s(NVCC) -c %s(CUFLAGS) %s<\n',DOLLAR,DOLLAR,DOLLAR);
else
fprintf(file,'%%.o : %%.c\n');
fprintf(file,' %s(CC) -c %s(CFLAGS) %s<\n',DOLLAR,DOLLAR,DOLLAR);
fprintf(file,'\n');
fprintf(file,'%%.o : %%.cpp\n');
fprintf(file,' %s(CC) -c %s(CFLAGS) %s<\n',DOLLAR,DOLLAR,DOLLAR);
end
fprintf(file,'\n');

for i=1:length(userSources)
objFileName = code_unix_change_ext(userSources{i}, 'o');
fprintf(file,'%s : %s\n',objFileName,escapePathStr(userSources{i}));
if gTargetInfo.codingGPU
fprintf(file,' %s(NVCC) -c %s(CUFLAGS_NO_RDC) %s\n',DOLLAR,DOLLAR,escapePathStr(userSources{i}));
else
fprintf(file,' %s(CC) -c %s(CFLAGS) %s\n',DOLLAR,DOLLAR,escapePathStr(userSources{i}));
end
end

for i=1:length(thirdPartySourcePaths)
if coder.make.internal.isRelativePath(thirdPartySourcePaths{i})
thirdPartySourcePaths{i} = [fileNameInfo.projectDirArray{1}, filesep, thirdPartySourcePaths{i}];
end
end
for i=1:length(thirdPartySources)
fullSrcName = CGXE.Utils.tokenizeFileFromModel(thirdPartySources{i}, modelName, thirdPartySourcePaths);
objFileName = code_unix_change_ext(thirdPartySources{i}, 'o');
fprintf(file,'%s : %s\n',objFileName,escapePathStr(fullSrcName));
if gTargetInfo.codingGPU
fprintf(file,' %s(NVCC) -c %s(CUFLAGS_NO_RDC) %s\n',DOLLAR,DOLLAR,escapePathStr(fullSrcName));
else
fprintf(file,' %s(CC) -c %s(CFLAGS) %s\n',DOLLAR,DOLLAR,escapePathStr(fullSrcName));
end
end

fclose(file);

function result = code_unix_change_ext(filename, ext)

[~, name_str] = fileparts(filename);

result = [name_str '.' ext];

function linkObjStr = getLinkObjStringForGroup(buildInfo,group, excludeGroups)
%Helper function to create a string that contatenates the Link objects in
%the platform specific format for a given group.
if nargin < 3
excludeGroups ={};
end
linkObjs = buildInfo.getLinkObjects(group,excludeGroups);
linkObjStr = '';
for iL= 1:numel(linkObjs)
currLinkObjPath = escapePathStr(strrep(linkObjs(iL).Path,'$(MATLAB_ROOT)',matlabroot));
if any(ismember(group,{'SFCLIB','USER_LIBS','LINK_MACHINE_LIBS', ...
'AUX_LNK_OBJS'})) || isempty(group)
%Third Party Library have empty group
linkObjStr = [linkObjStr currLinkObjPath filesep linkObjs(iL).Name ' ']; %#ok<AGROW>
else
linkObjStr = [linkObjStr '-L' currLinkObjPath ' -l' linkObjs(iL).Name ' ']; %#ok<AGROW>

end
end
function str = getCatString(incell)
%Conatenate all the strings in cell array of strings.
str = sprintf('%s ',incell{:});
if ~isempty(str)
str(end) = [];
end

function escStr = escapePathStr(inpath)
% Escape scapces in path so that the makefile will work with directories
% having spaces in their path
escStr = regexprep(strtrim(inpath),' ','\\ ');