gusucode.com > private工具箱matlab源码程序 > private/generate_code_for_charts_and_machine.m

    function generate_code_for_charts_and_machine(fileNameInfo,codingRebuildAll)

% Copyright 2003-2015 The MathWorks, Inc.
 

   global gMachineInfo
   global gTargetInfo

   incCodeGenInfo = compute_inc_codegen_info(fileNameInfo,codingRebuildAll);
   display_startup_message(fileNameInfo);

   mainMachineId = gMachineInfo.mainMachineId;
   machineName = gMachineInfo.machineName;
   mainMachineName = gMachineInfo.mainMachineName;
   targetName = gMachineInfo.targetName;

   gMachineInfo.thirdPartyUses = {};
   gMachineInfo.updateBuildInfoArgs = {};

   lastException = [];

   if ~gTargetInfo.codingHDL && ~gTargetInfo.codingPLC
       fileNameInfo.complex_number_types = ...
           strcmpi(get_param(mainMachineName, 'SupportComplex'), 'on');
       % Later, in code_rtwtypesdoth(), we claim the MaxMultiwordBits is
       % 1024, which definitely requires multiword typedefs
       fileNameInfo.multiword_types = true;
   end

    if gTargetInfo.codingSFunction
        compute_autoinheritance_info();
    end

   for i = 1:length(gMachineInfo.charts)
        chart = gMachineInfo.charts(i);
        chartFileNumber = sf('get',chart,'chart.chartFileNumber');
        chartName = sf('get',chart,'.name');

        numSpecs = length(gMachineInfo.specializations{i});

        if gTargetInfo.codingSFunction
            for j = 1:numSpecs
                if(~incCodeGenInfo.flags{i}(j))
                    
                    success = false;
                    try
                        mainSfunName = [gMachineInfo.mainMachineName '_sfun'];
                        thirdPartyUses = feval(mainSfunName, 'get_third_party_uses_info', gMachineInfo.machineName, ...
                            chartFileNumber, gMachineInfo.specializations{i}{j});
                        gMachineInfo.thirdPartyUses = [gMachineInfo.thirdPartyUses  thirdPartyUses];
                        
                        updateBuildInfoArgs = feval(mainSfunName, 'get_updateBuildInfo_args_info', gMachineInfo.machineName, ...
                            chartFileNumber, gMachineInfo.specializations{i}{j});
                        gMachineInfo.updateBuildInfoArgs = [gMachineInfo.updateBuildInfoArgs  updateBuildInfoArgs];
                        
                        success = true;
                    catch
                    end
                    
                    if ~success
                        incCodeGenInfo.flags{i}(j) = 1;
                    end
                end
            end
        end
        
        if ~any(incCodeGenInfo.flags{i})
            continue;
        end
            
        compute_chart_information(chart);
        
        if gTargetInfo.codingRTW
            rtwInstanceInfo = [];
        end

        % if/when we support library charts, the key will need to be augmented
        % to distinguish between specializations, and this flush will need to
        % be moved into the spec loop below.  will also need a way to distinguish
        % keys from instances in different models.
        if gTargetInfo.codingSFunction ...
                && isfile([fullfile(matlabroot,'toolbox','fixedpoint','fixedpoint','+fixed','+internal','clearLog') '.' mexext])
            % Do NOT test for min/max logging enabled - especially
            % important to flush when not enabled.
            fixed.internal.clearLog(['#' Simulink.ID.getSID(idToHandle(sfroot(), chart))]);
        end
        
        %Clear any chart cache auxInfo before generating code.
        sfprivate('auxInfoChartCache','clr',chart);
        numSpecs = length(gMachineInfo.specializations{i});
        for j = 1:numSpecs
            thisSpec = gMachineInfo.specializations{i}{j};
            if(~isempty(incCodeGenInfo.jitIncCodegenInfoForMachine))
                jitIncCodegenInfoForSpec = incCodeGenInfo.jitIncCodegenInfoForMachine.(thisSpec);
                needsPreFallback = jitIncCodegenInfoForSpec.needsPreFallback;
                preFallBackReason = jitIncCodegenInfoForSpec.preFallBackReason;
            else
                needsPreFallback = true;
                preFallBackReason = 'feature off';
            end
            if(~incCodeGenInfo.flags{i}(j))
                continue;
            end
            
            %TLTODO: handle following block
            % Let EML know what charts need to be reconsidered for its resolved functions
            targetId = gTargetInfo.target;
            targetName = sf('get',targetId,'.name');
            targetName0 = sfprivate('get_eml_metadata_target_name',targetName);
            machineName0 = sfprivate('get_eml_metadata_machine_name',machineName);
            rebuildMetaData = sf('get', mainMachineId, '.eml.rebuildMetaData');
            if ~isempty(rebuildMetaData) && isfield(rebuildMetaData, targetName0)
                chartFiles = rebuildMetaData.(targetName0).(machineName0).rebuiltChartFiles;
                if ~any(chartFiles == chartFileNumber)
                    chartFiles = sort([chartFiles chartFileNumber]);
                    rebuildMetaData.(targetName0).(machineName0).rebuiltChartFiles = chartFiles;
                    sf('set',mainMachineId,'.eml.rebuildMetaData', rebuildMetaData);
                end
            end
                
            % Even though the incremental codegen info says we need to
            % regenerate IR for this spec, it is possible this spec was
            % handled as part of another chart. Hence, try to relink before
            % we generate code and return early.
            if gTargetInfo.codingSFunction && ...
               ~needsPreFallback && ...
               Stateflow.JIT.Utils.relinkToExistingJITEngine(chart,thisSpec, false)
                gMachineInfo.codingLLVM{i}(j) = 1;
                continue;
            end
            
            display_chart_codegen_message(chart,sf('get',targetId,'target.name'));        
            errorsOccurred = false;
            try
               needsPreFallback = construct_module(chart, 0.0, thisSpec, fileNameInfo,needsPreFallback,preFallBackReason);
            catch ME
                errorsOccurred = true;                
                lastException = ME;     
                sfprivate('sf_display', sprintf('Error: %s\n', ME.message));
            end

            if ~errorsOccurred
                if gTargetInfo.codingSFunction && ...
                   ~needsPreFallback && ...
                   sfprivate('can_relink_to_existing_jit_engine',chart,thisSpec)
                    gMachineInfo.codingLLVM{i}(j) = 1;
                    sf('Cg','destroy_module',chart);
                    continue;
                end

                sfprivate('sf_compile_stats', 'snap', targetName, mainMachineName, machineName, chartName, 'generate_code_for_chart', true);

                try
                    create_project_dir_path_just_in_time(fileNameInfo);
                    sf('set', chart, 'chart.codeGeneratedNow', 1);

                    msgString = sprintf('Generating files:\n');
                    sfprivate('sf_display', msgString);

                    code_chart_header_file(fileNameInfo,chart,j);
                    code_chart_source_file(fileNameInfo,chart,j);

                    spec_third_party_uses = sf('Cg','third_party_uses',chart);
                    gMachineInfo.thirdPartyUses = [gMachineInfo.thirdPartyUses spec_third_party_uses];

                    spec_updateBuildInfoArgs = sf('Cg','updateBuildInfo_args',chart);
                    gMachineInfo.updateBuildInfoArgs = [gMachineInfo.updateBuildInfoArgs spec_updateBuildInfoArgs];

                catch ME 
                    % Make sure we destroy the module otherwise things leak.
                    if (sf('feature', 'Single pass for RTW code generation') == 0) || ~gTargetInfo.codingRTW % We delay the destruction at the end of mdlRTWCG(). Needs to be delayed in this case since the order of deletion can be different from the order of creation.
                        sf('Cg','destroy_module',chart);
                    end
                    rethrow(ME);
                end

                if (sf('feature', 'Single pass for RTW code generation') == 0) || ~gTargetInfo.codingRTW
                    sf('Cg','destroy_module',chart);
                end

                sfprivate('sf_compile_stats', 'snap', targetName, mainMachineName, machineName, chartName, 'generate_code_for_chart', false);
                
                if gTargetInfo.codingRTW
                    tlcFile = fileNameInfo.chartTLCFiles{i}{j};
                    outputFcn = fileNameInfo.chartOutputsFcns{i}{j};
                    initFcn = fileNameInfo.chartInitializeFcns{i}{j};

                    instanceInfo = get_instance_rtw_info(chart, thisSpec, tlcFile, outputFcn, initFcn, ...
                        spec_third_party_uses, spec_updateBuildInfoArgs);
                    rtwInstanceInfo = [rtwInstanceInfo instanceInfo]; %#ok<AGROW>
                end
            end
        end
        
        if gTargetInfo.codingRTW
            sf('set', chart, 'chart.rtwInfo.instanceInfo', rtwInstanceInfo);
        end
   end

   if gTargetInfo.codingSFunction && ~isempty(lastException)
       throwAsCaller(lastException);
   end

   % Compute if machine is fully jitted. if not we will have to run the
   % makemethod in targetman
   if gTargetInfo.codingSFunction && sf('Feature','Sim Through JIT')
        jitIncCodegenInfo = sf('get',mainMachineId,'machine.jitIncCodeGenInfo');
        if(~isempty(jitIncCodegenInfo) && isfield(jitIncCodegenInfo,machineName))
            jitIncCodegenInfoForMachine = jitIncCodegenInfo.(machineName);
        else
            jitIncCodegenInfoForMachine  = [];
        end

        if ~isempty(gMachineInfo.charts) && ~isempty(jitIncCodegenInfoForMachine)
           codegenSpecCount = 0;
           foundInJitSpecCount = 0;
           foundInDllSpecCount = 0;
           for i = 1:length(gMachineInfo.charts)
               chart = gMachineInfo.charts(i);
               numSpecs = length(gMachineInfo.specializations{i});
               for j=1:numSpecs
                   thisSpec = gMachineInfo.specializations{i}{j};
                   jitIncCodegenInfoForSpec = jitIncCodegenInfoForMachine.info.(thisSpec);
                   if(jitIncCodegenInfoForSpec.generateCode)
                       codegenSpecCount = codegenSpecCount+1;
                       break;
                   elseif(jitIncCodegenInfoForSpec.generateJitEngine)
                       if(~sfprivate('can_relink_to_existing_jit_engine',chart,thisSpec))
                           % must have been a late fallback
                           codegenSpecCount = codegenSpecCount+1;
                       else
                           foundInJitSpecCount = foundInJitSpecCount+1;
                       end
                   elseif(jitIncCodegenInfoForSpec.foundInDll)
                       foundInDllSpecCount = foundInDllSpecCount+1;
                   else
                       assert(jitIncCodegenInfoForSpec.foundInJit);
                       foundInJitSpecCount = foundInJitSpecCount+1;
                   end
               end
           end
           jitIncCodegenInfo.(machineName).codegenSpecCount = codegenSpecCount;
           if(jitIncCodegenInfo.(machineName).codegenSpecCount>0)
                jitIncCodegenInfo.(machineName).invokeMakeMethod = true;
           end
           jitIncCodegenInfo.(machineName).foundInJitSpecCount = foundInJitSpecCount;
           jitIncCodegenInfo.(machineName).foundInDllSpecCount = foundInDllSpecCount;
           sf('set',mainMachineId,'machine.jitIncCodeGenInfo',jitIncCodegenInfo);
        end

       fullyJittedLibs = [];
       for i = 1:length(fileNameInfo.linkMachines)
           linkMachineName = fileNameInfo.linkMachines{i};
           if(jitIncCodegenInfo.(linkMachineName).codegenSpecCount==0 &&...
              jitIncCodegenInfo.(linkMachineName).foundInDllSpecCount==0)
               fullyJittedLibs(end+1) = i;  %#ok <AGROW>
           end
       end

       fileNameInfo.linkMachines(fullyJittedLibs) = [];
       fileNameInfo.linkLibFullPaths(fullyJittedLibs) = [];
       fileNameInfo.linkObjListFullPaths (fullyJittedLibs) = [];
       fileNameInfo.linkMachinesInlinable(fullyJittedLibs) = [];

       codegenOccurred = false;
       for i = 1:length(fileNameInfo.linkMachines)
           linkMachineName = fileNameInfo.linkMachines{i};
           if(jitIncCodegenInfo.(linkMachineName).codegenSpecCount>0)
                codegenOccurred = true;
                break;
           end
       end
       if(jitIncCodegenInfo.(machineName).codegenSpecCount>0)
           codegenOccurred = true;
       end
       if(~codegenOccurred)
            return;
       end
       jitIncCodegenInfo.(machineName).invokeMakeMethod = true;
       sf('set',mainMachineId,'machine.jitIncCodeGenInfo',jitIncCodegenInfo);
   end

   if gTargetInfo.codingSFunction
       gMachineInfo.thirdPartyUses = unique(gMachineInfo.thirdPartyUses);
       gMachineInfo.updateBuildInfoArgs = uniqueCell(gMachineInfo.updateBuildInfoArgs);
   end 
   
   if ~gTargetInfo.codingHDL && ~gTargetInfo.codingPLC
       oldCtxInfo = []; % Only set when we create a temporary context for machine.
       if sf('feature', 'Single pass for RTW code generation') && gTargetInfo.codingRTW
           % Create a temporary context for machine since the current 
           % context is the one from RTW and we do not want to pollute it 
           % with machine information that are not compatible with RTW. 
           %
           % To be consistent with other created contexts, this temporary 
           % context will be destroyed the next time that we create a new 
           % context and calling construct_module or construct_machine_module.
           % Thus, we do not need to destroy the context here.
           
           oldCtxInfo = gMachineInfo.ctxInfo;
           status = construct_context_for_machine([], true);
           if status ~= 0
               construct_coder_error(gMachineInfo.machineId,'The construction of the context for the machine did not worked.',0);
           end
       end
       
       try
           sf('Cg','construct_machine_module',gMachineInfo.ctxInfo);
       catch ME
           lastException = ME;
           construct_coder_error(gMachineInfo.machineId,ME.message,0);
       end

       if isempty(lastException)
           assert(sfprivate('coder_error_count_man', 'get') == 0);
           sfprivate('sf_compile_stats', 'snap', targetName, mainMachineName, machineName, 'machine', 'generate_code_for_machine', true);
           create_project_dir_path_just_in_time(fileNameInfo);
           fileNameInfo = code_aux_support_files(fileNameInfo);

           if gTargetInfo.codingSFunction
              generate_sfcn_customcode_files(fileNameInfo);
           end

           code_machine_header_file(fileNameInfo);
           code_machine_source_file(fileNameInfo);
           code_interface_and_support_files(fileNameInfo);
           sfprivate('sf_compile_stats', 'snap', targetName, mainMachineName, machineName, 'machine', 'generate_code_for_machine', false);
       end
       
       if ~isempty(oldCtxInfo)
           % No need to delete the temporary context for the machine 
           % (see the previous comment), but we need to restore the old context.
           gMachineInfo.ctxInfo = oldCtxInfo;
       end
   end

   if ~isempty(lastException)
       throwAsCaller(lastException);
   end
    
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function display_startup_message(fileNameInfo)
   global gMachineInfo
   if(~sf('Feature','Sim Through JIT'))
       msgString = sprintf('Code Directory :\n     "%s"\n',fileNameInfo.targetDirName);
       sfprivate('sf_display',msgString);

       msgString = sprintf('Machine (#%d): "%s"  Target : "%s"\n',gMachineInfo.machineId,gMachineInfo.machineName,gMachineInfo.targetName);
       sfprivate('sf_display',msgString);
   end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function y_or_n = yes_or_no(val)
    if val
        y_or_n = 'Yes';
    else
        y_or_n = 'No';
    end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function instanceInfo = get_instance_rtw_info(chart, spec, tlcFile, outputFcn, initFcn, spec_third_party_uses, spec_updateBuildInfo_args)

    instanceInfo.specialization = spec;
    instanceInfo.TLCFile = tlcFile;
    instanceInfo.OutputsFcn = outputFcn;
    instanceInfo.InitializeFcn = initFcn;
    instanceInfo.ReusableOutputs = sf('get', chart, 'chart.rtwInfo.reusableOutputs');
    instanceInfo.ExpressionableInputs = sf('get', chart, 'chart.rtwInfo.expressionableInputs');
    instanceInfo.Inline = yes_or_no(sf('get', chart, 'chart.rtwInfo.chartWhollyInlinable'));
    instanceInfo.sfSymbols = sf('get', chart, 'chart.rtwInfo.sfSymbols');
    instanceInfo.gatewayCannotBeInlinedMultipleTimes = sf('get', chart, 'chart.rtwInfo.gatewayCannotBeInlinedMultipleTimes');
    instanceInfo.accessesMachineSymbols = sf('get', chart, 'chart.rtwInfo.accessesMachineSymbols');
    instanceInfo.outputEventsWithMultipleCallers = sf('get', chart, 'chart.rtwInfo.outputEventsWithMultipleCallers');
    instanceInfo.dworkInfo = sf('get', chart, 'chart.rtwInfo.dWorkVarInfo');
    instanceInfo.dworkChecksum = sfprivate('md5', rmfield(instanceInfo.dworkInfo, {'varName', 'typeSize', 'isOpaque', 'bitWidth', 'description', 'extModeUpload', 'isTestPoint', 'objName', 'path', 'resolveToSignalObject'}));
    instanceInfo.requiredStackSize = sf('get', chart, 'chart.rtwInfo.requiredStackSize');
    instanceInfo.thirdPartyUses = spec_third_party_uses;
    instanceInfo.updateBuildInfoArgs = spec_updateBuildInfo_args;
    instanceInfo.chartUsesVerify = sf('get', chart, 'chart.sfunInfo.chartUsesVerify');

function c = uniqueCell(c)
% Behaves like a UNIQUE command but on a cell array.
duplicateIdx = [];
for i = 1:numel(c)
    if ~any(i ==  duplicateIdx)
        for j = i+1:numel(c)
            if isequal(c(i),c(j))
                duplicateIdx = [duplicateIdx j]; %#ok<AGROW>
            end
        end
    end
end
c(duplicateIdx) = [];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function generate_sfcn_customcode_files(fileNameInfo)

   global gMachineInfo

   % Generate the extra files for the custom init/term functions
   % before calling the instrumenter
   if gMachineInfo.ctxInfo.sfcnTgtCustomCodeInfo.hasExtraCustomCodeFiles
      code_sfun_customcode_header_file(fileNameInfo);
      code_sfun_customcode_source_file(fileNameInfo);
   end

   % Code coverage special case: run the instrumenter before emitting the
   % machine code in order to include global instrumentation symbols
   if ~isempty(gMachineInfo.ctxInfo.sfcnTgtCustomCodeInfo.instrumenter)
      extraFilesToInstrument = [];
      if gMachineInfo.ctxInfo.sfcnTgtCustomCodeInfo.hasExtraCustomCodeFiles
         % Add the extra source file containing the custom init/term functions
         extraFilesToInstrument = {fullfile(fileNameInfo.targetDirName, fileNameInfo.customCodeSourceFile)};
      end
      gMachineInfo.ctxInfo.sfcnTgtCustomCodeInfo.instrumenter.configureBuildInfo(fileNameInfo, extraFilesToInstrument);
      if ~gMachineInfo.ctxInfo.sfcnTgtCustomCodeInfo.instrumenter.instrument(gMachineInfo)
         % An error occured then ignore the code instrumentation
         gMachineInfo.ctxInfo.sfcnTgtCustomCodeInfo.instrumenter = [];
      end
   end

   % Generate the header file containing the forward declarations
   % for custom code coverage.
   if gMachineInfo.ctxInfo.sfcnTgtCustomCodeInfo.supportCoverage
      code_sfun_customcode_cov_header_file(fileNameInfo);
   end