classdef XilCompInfo < handle
%XilCompInfo is container for compiler information required by XIL

%   Copyright 2018-2023 The MathWorks, Inc.
    
    % Make properties transient to enforce the assumption that this object never needs to be serialized.
    properties(Transient, GetAccess=public, SetAccess=private)
        XilMexCompInfo;
        ToolchainOrTMF;
        BuildConfiguration;
        CustomToolchainOptions;
        XilLibraryExt;
        LegacyTargetLibSuffix;
    end
    
    properties(Dependent=true, GetAccess=public, SetAccess=private)
        ToolchainInfo;
        TMFProperties;
        IsToolchainBased;
    end
    
    methods
        function val = get.ToolchainInfo(this)
            if isa(this.ToolchainOrTMF, 'coder.make.internal.TMFProps')
                val = this.ToolchainOrTMF.Toolchain;
            else
                val = this.ToolchainOrTMF;
            end         
        end
        
        function val = get.TMFProperties(this)
            if isa(this.ToolchainOrTMF, 'coder.make.internal.TMFProps')
                val = this.ToolchainOrTMF;
            else
                val = [];
            end         
        end

        function val = get.IsToolchainBased(this)
            val = coder.make.internal.isToolchainObject(this.ToolchainOrTMF);
        end
    end
    
    properties(GetAccess=public, SetAccess=private, Dependent=true)
        XilMexCompilerKey;
    end
    
    methods(Access=private, Static=true)
        
        function [lToolchain, lBuildConfiguration, ...
                 lCustomToolchainOptions] = ...
                getDefaultCompInfo(lDefaultMexCompInfo, gpuEnabled)
            arguments
                lDefaultMexCompInfo
                gpuEnabled = false
            end
            
            tcName = coder.make.internal.getDefaultToolchain('CompStruct', lDefaultMexCompInfo, 'GPUEnabled', gpuEnabled);
            lToolchain = coder.make.internal.getToolchainInfoFromRegistry(tcName);

            % Default values
            lBuildConfiguration = coder.make.ToolchainInfo.getDefaultBuildConfig;
            lCustomToolchainOptions = {};
        end
    end
           
    
    methods
        
        function lMexCompilerKey = get.XilMexCompilerKey(this)
            
            if isempty(this.XilMexCompInfo)
                lMexCompilerKey = '';
            else
                lMexCompilerKey = this.XilMexCompInfo.compStr;
            end
            
        end
    end
        
    methods (Access=public, Static=true)
        
        function lXilCompInfo = createXilCompInfoForSilAndPws...
                (lMexCompInfoDefault, varargin)
            
            lLegacyTargetLibSuffix = '';
            
            lMexCompInfo = lMexCompInfoDefault.DefaultMexCompInfo;
                
            [lToolchainOrTMF, lBuildConfiguration, lCustomToolchainOptions] = ...
                coder.internal.utils.XilCompInfo.getDefaultCompInfo...
                (lMexCompInfo);
            
            if(nargin>1)
                ToolChainName = varargin{1};
                if (usesCUDAToolchain(ToolChainName))
                    lToolchainOrTMF = coder.internal.getToolchainInfoFromConfigParam(ToolChainName, lMexCompInfo, false, false);
                end
            end
            
            lXilCompInfo = coder.internal.utils.XilCompInfo...
                (lMexCompInfo, lToolchainOrTMF, lBuildConfiguration, ...
                 lCustomToolchainOptions, lLegacyTargetLibSuffix);
        end
        
        
        function lXilCompInfo = slCreateXilCompInfo(cs, lMexCompInfoDefault, lIsSilAndPws)
            
            if ischar(cs) || isstring(cs)
                %@TODO(g1932312, remove this line when all call-sites are updated)
                cs = getActiveConfigSet(cs);
            end
                
            if lIsSilAndPws
            
                lLegacyTargetLibSuffix = '';
                
                lMexCompInfo = lMexCompInfoDefault.DefaultMexCompInfo;
                
                isGPU = coder.internal.getIsGPUAndGPUHardwareFromConfigSet(cs);
                [lToolchainOrTMF, lBuildConfiguration, lCustomToolchainOptions] = ...
                    coder.internal.utils.XilCompInfo.getDefaultCompInfo...
                    (lMexCompInfo, isGPU);
            else 
                [lToolchainOrTMF, lBuildConfiguration, lLegacyTargetLibSuffix, ...
                lCustomToolchainOptions, lMexCompilerKey] = ...
                    coder.internal.getCompilationDataFromConfigSet...
                    (cs, lMexCompInfoDefault.DefaultMexCompInfo);  

                lMexCompInfo = coder.make.internal.getMexCompInfoFromKey(lMexCompilerKey);
            end
            
            lXilCompInfo = coder.internal.utils.XilCompInfo...
                (lMexCompInfo, lToolchainOrTMF, lBuildConfiguration, ...
                 lCustomToolchainOptions, lLegacyTargetLibSuffix);
        end
        
        function lXilCompInfo = mlCreateXilCompInfo(lConfig)          
                        
            lToolchain = lConfig.Toolchain;
            if coder.make.internal.useDefaultToolchain(lToolchain)
                lToolchain = coder.make.internal.getDefaultToolchain();
            end
            
            if ~isempty(lToolchain)
                toolchainInfo = coder.make.internal.getToolchainInfoFromRegistry(lToolchain);
            else
                toolchainInfo = [];
            end
            
            if ~isempty(toolchainInfo) && toolchainInfo.SupportsBuildingMEXFuncs
                lMexCompilerKey = toolchainInfo.Alias{1};
                lMexCompInfo = coder.make.internal.getMexCompInfoFromKey(lMexCompilerKey);
            else
                lMexCompInfo = [];
            end      
            
            lToolchainOrTMF = toolchainInfo;
            
            lBuildConfiguration = lConfig.BuildConfiguration;
            if isempty(lBuildConfiguration)
                lBuildConfiguration = 'Faster Builds';
            end

           if strcmp(lBuildConfiguration, 'Specify')
               lCustomToolchainOptions = lConfig.CustomToolchainOptions;
           else
               lCustomToolchainOptions = {};
           end      
           
           % No legacy target library suffix for MATLAB Coder case
           lLegacyTargetLibSuffix = '';
           
           lXilCompInfo = coder.internal.utils.XilCompInfo...
               (lMexCompInfo, ...
                lToolchainOrTMF, lBuildConfiguration, ...
                lCustomToolchainOptions, lLegacyTargetLibSuffix);
       end
       
    end
    
    methods(Access=private)
        
        function this = XilCompInfo...
                (lMexCompInfo, lToolchainOrTMF, ...
                 lBuildConfiguration, lCustomToolchainOptions, ...
                 lLegacyTargetLibSuffix)

            this.XilMexCompInfo = lMexCompInfo;
            this.ToolchainOrTMF = lToolchainOrTMF;
            this.BuildConfiguration = lBuildConfiguration;
            this.CustomToolchainOptions = lCustomToolchainOptions;
            this.XilLibraryExt  = i_getLibraryExt(this.ToolchainInfo, ...
                lLegacyTargetLibSuffix);
            this.LegacyTargetLibSuffix = lLegacyTargetLibSuffix;
        end
    end
end


function ext = i_getLibraryExt(lToolchainInfo, lLegacyTargetLibSuffix)
    if isempty(lToolchainInfo)
        if isempty(lLegacyTargetLibSuffix)
            ext = ['.' coder.make.internal.getLibExtension()];
        else
            [~, ~, ext] = fileparts(lLegacyTargetLibSuffix);
            assert(~isempty(ext), ...
                sprintf('Could not extract extension from TargetLibSuffix ''%s''', ...
                lLegacyTargetLibSuffix));
        end
    else
        ext = coder.make.internal.getLibExtension(lToolchainInfo);
    end
end

function CUDAToolchain = usesCUDAToolchain(tcNameFromCs)
CUDAToolchain = false;
if(~isempty(tcNameFromCs) && startsWith(tcNameFromCs,'NVIDIA CUDA'))
    CUDAToolchain = true;
    return;
end

end
