function pasa_make()
    %% ------------------ Create log file of installation ------------------ %%
    % diary mex_install_log.txt

    %% ------------------ Set installation bypass options ------------------ %%
    % Option for bypassing compilation of CHOLMOD objects (for debugging)
    bypass_cholmod = false ; % Default should be false for regular installation
    % Option for bypassing compilation of solver (PASA, etc.) objects (for dbug)
    bypass_objects = false ; % Default should be false for regular installation
    % Option for bypassing cleanup of objects (for debugging)
    bypass_cleanup = false ; % Default value should be false 

    %% ------------------ Compile the CHOLMOD object files ------------------ %%
    % Initialize details variable to 0 
    details = 0 ;
    % location of SuiteSparse directory
    SuiteSparsePath = '../../SuiteSparseX/' ;
    MATLABpath = strcat(SuiteSparsePath, 'CHOLMOD/MATLAB/') ;
    
    v = version ;
    try
        % ispc does not appear in MATLAB 5.3
        pc = ispc ;
        mac = ismac ;
    catch                                                                       %#ok
        % if ispc fails, assume we are on a Windows PC if it's not unix
        pc = ~isunix ;
        mac = 0 ;
    end
    
    flags = '' ;
    is64 = ~isempty (strfind (computer, '64')) ;
    if (is64)
        % 64-bit MATLAB
        flags = '-largeArrayDims' ;
    end

    % MATLAB 8.3.0 now has a -silent option to keep 'mex' from burbling too much
    if (~verLessThan ('matlab', '8.3.0'))
        flags = ['-silent ' flags] ;
    end
    
    %% ----- Set include string to all directories to be included ----- %%
    % list of subdirectories of SuiteSparse to include in mex compilation of pasa
    include_dir = {'AMD/Include/', ...
                   'COLAMD/Include/', ...
                   'CCOLAMD/Include/', ...
                   'CAMD/Include/', ...
                   'CHOLMOD/Include/', ...
                   'SuiteSparse_config/'} ;
    
    include = ['-I"' MATLABpath '"'] ;
    for f = include_dir
        ff = strcat(SuiteSparsePath, f {1}) ;
        include = [include ' -I"' ff '"'] ;
    end
    
    if (verLessThan ('matlab', '7.0'))
        % do not attempt to compile CHOLMOD with large file support
        include = [include ' -DNLARGEFILE'] ;
    elseif (~pc)
        % Linux/Unix require these flags for large file support
        include = [include ' -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE'] ;
    end
    
    if (verLessThan ('matlab', '6.5'))
        % logical class does not exist in MATLAB 6.1 or earlie
        include = [include ' -DMATLAB6p1_OR_EARLIER'] ;
    end
    
    % Determine if METIS is available
    metis_path = strcat(SuiteSparsePath, 'metis-5.1.0') ;
    have_metis = exist (metis_path, 'dir') ;
    
    % If METIS is available add necessary include directories
    if (have_metis)
        fprintf ('Compiling CHOLMOD with METIS 5.1.0 for MATLAB Version %s\n', v) ;
        include = [include ' -I' metis_path '/include'] ;
        include = [include ' -I' metis_path '/GKlib'] ;
        include = [include ' -I' metis_path '/libmetis'] ;
    else
        fprintf ('Compiling CHOLMOD without METIS for MATLAB Version %s\n', v) ;
        include = ['-DNPARTITION ' include] ;
    end
    
    %---------------------------------------------------------------------------
    % BLAS option
    %---------------------------------------------------------------------------
    
    % This is exceedingly ugly. The MATLAB mex command needs to be told where to
    % find the LAPACK and BLAS libraries, which is a real portability nightmare.
    
    if (pc)
        if (verLessThan ('matlab', '7.5'))
            lapack = 'libmwlapack.lib' ;
        else
            lapack = 'libmwlapack.lib libmwblas.lib' ;
        end
    else
        if (verLessThan ('matlab', '7.5'))
            lapack = '-lmwlapack' ;
        else
            lapack = '-lmwlapack -lmwblas' ;
        end
    end
    
    if (is64 && ~verLessThan ('matlab', '7.8'))
        % versions 7.8 and later on 64-bit platforms use a 64-bit BLAS
        fprintf ('with 64-bit BLAS\n') ;
        flags = [flags ' -DBLAS64'] ;
    end
    
    if (~(pc || mac))
        % for POSIX timing routine
        lapack = [lapack ' -lrt'] ;
    end
    
    
    %---------------------------------------------------------------------------
    config_path = strcat(SuiteSparsePath, ...
                                      'SuiteSparse_config/SuiteSparse_config') ;
    config_src = { config_path } ;

    ordering_src = { ...
        'AMD/Source/amd_1', ...
        'AMD/Source/amd_2', ...
        'AMD/Source/amd_aat', ...
        'AMD/Source/amd_control', ...
        'AMD/Source/amd_defaults', ...
        'AMD/Source/amd_dump', ...
        'AMD/Source/amd_global', ...
        'AMD/Source/amd_info', ...
        'AMD/Source/amd_order', ...
        'AMD/Source/amd_postorder', ...
        'AMD/Source/amd_post_tree', ...
        'AMD/Source/amd_preprocess', ...
        'AMD/Source/amd_valid', ...
        'CAMD/Source/camd_1', ...
        'CAMD/Source/camd_2', ...
        'CAMD/Source/camd_aat', ...
        'CAMD/Source/camd_control', ...
        'CAMD/Source/camd_defaults', ...
        'CAMD/Source/camd_dump', ...
        'CAMD/Source/camd_global', ...
        'CAMD/Source/camd_info', ...
        'CAMD/Source/camd_order', ...
        'CAMD/Source/camd_postorder', ...
        'CAMD/Source/camd_preprocess', ...
        'CAMD/Source/camd_valid', ...
        'COLAMD/Source/colamd', ...
        'CCOLAMD/Source/ccolamd'} ;

    % Update ordering source to be located in SuiteSparse directory
    for k = 1:length(ordering_src)
        ordering_src {k} = strcat(SuiteSparsePath, ordering_src {k}) ;
    end
    
    if (have_metis)
        metis_src = {
            'GKlib/b64', ...
            'GKlib/blas', ...
            'GKlib/csr', ...
            'GKlib/error', ...
            'GKlib/evaluate', ...
            'GKlib/fkvkselect', ...
            'GKlib/fs', ...
            'GKlib/getopt', ...
            'GKlib/gkregex', ...
            'GKlib/graph', ...
            'GKlib/htable', ...
            'GKlib/io', ...
            'GKlib/itemsets', ...
            'GKlib/mcore', ...
            'GKlib/memory', ...
            'GKlib/omp', ...
            'GKlib/pdb', ...
            'GKlib/pqueue', ...
            'GKlib/random', ...
            'GKlib/rw', ...
            'GKlib/seq', ...
            'GKlib/sort', ...
            'GKlib/string', ...
            'GKlib/timers', ...
            'GKlib/tokenizer', ...
            'GKlib/util', ...
            'libmetis/auxapi', ...
            'libmetis/balance', ...
            'libmetis/bucketsort', ...
            'libmetis/checkgraph', ...
            'libmetis/coarsen', ...
            'libmetis/compress', ...
            'libmetis/contig', ...
            'libmetis/debug', ...
            'libmetis/fm', ...
            'libmetis/fortran', ...
            'libmetis/frename', ...
            'libmetis/gklib', ...
            'libmetis/graph', ...
            'libmetis/initpart', ...
            'libmetis/kmetis', ...
            'libmetis/kwayfm', ...
            'libmetis/kwayrefine', ...
            'libmetis/mcutil', ...
            'libmetis/mesh', ...
            'libmetis/meshpart', ...
            'libmetis/minconn', ...
            'libmetis/mincover', ...
            'libmetis/mmd', ...
            'libmetis/ometis', ...
            'libmetis/options', ...
            'libmetis/parmetis', ...
            'libmetis/pmetis', ...
            'libmetis/refine', ...
            'libmetis/separator', ...
            'libmetis/sfm', ...
            'libmetis/srefine', ...
            'libmetis/stat', ...
            'libmetis/timing', ...
            'libmetis/util', ...
            'libmetis/wspace'} ;
    
        for i = 1:length (metis_src)
            metis_src {i} = [metis_path '/' metis_src{i}] ;
        end
    end
    
    cholmod_matlab = { [MATLABpath 'cholmod_matlab'] } ;
    
    cholmod_src = {
        '../Core/cholmod_aat', ...
        '../Core/cholmod_add', ...
        '../Core/cholmod_band', ...
        '../Core/cholmod_change_factor', ...
        '../Core/cholmod_common', ...
        '../Core/cholmod_complex', ...
        '../Core/cholmod_copy', ...
        '../Core/cholmod_dense', ...
        '../Core/cholmod_error', ...
        '../Core/cholmod_factor', ...
        '../Core/cholmod_memory', ...
        '../Core/cholmod_sparse', ...
        '../Core/cholmod_transpose', ...
        '../Core/cholmod_triplet', ...
        '../Check/cholmod_check', ...
        '../Check/cholmod_read', ...
        '../Check/cholmod_write', ...
        '../Cholesky/cholmod_amd', ...
        '../Cholesky/cholmod_analyze', ...
        '../Cholesky/cholmod_colamd', ...
        '../Cholesky/cholmod_etree', ...
        '../Cholesky/cholmod_factorize', ...
        '../Cholesky/cholmod_postorder', ...
        '../Cholesky/cholmod_rcond', ...
        '../Cholesky/cholmod_resymbol', ...
        '../Cholesky/cholmod_rowcolcounts', ...
        '../Cholesky/cholmod_rowfac', ...
        '../Cholesky/cholmod_solve', ...
        '../Cholesky/cholmod_spsolve', ...
        '../MatrixOps/cholmod_drop', ...
        '../MatrixOps/cholmod_horzcat', ...
        '../MatrixOps/cholmod_norm', ...
        '../MatrixOps/cholmod_scale', ...
        '../MatrixOps/cholmod_sdmult', ...
        '../MatrixOps/cholmod_ssmult', ...
        '../MatrixOps/cholmod_submatrix', ...
        '../MatrixOps/cholmod_vertcat', ...
        '../MatrixOps/cholmod_symmetry', ...
        '../Modify/cholmod_rowadd', ...
        '../Modify/cholmod_rowdel', ...
        '../Modify/cholmod_updown', ...
        '../Supernodal/cholmod_super_numeric', ...
        '../Supernodal/cholmod_super_solve', ...
        '../Supernodal/cholmod_super_symbolic', ...
        '../Partition/cholmod_ccolamd', ...
        '../Partition/cholmod_csymamd', ...
        '../Partition/cholmod_camd', ...
        '../Partition/cholmod_metis', ...
        '../Partition/cholmod_nesdis'} ;
    % Update cholmod source to be located in CHOLMOD directory
    for k = 1:length(cholmod_src)
        cholmod_src {k} = strcat(MATLABpath, cholmod_src {k}) ;
    end
    
    if (pc)
        % Windows does not have drand48 and srand48, required by METIS.  Use
        % drand48 and srand48 in CHOLMOD/MATLAB/Windows/rand48.c instead.
        % Also provide Windows with an empty <strings.h> include file.
        obj_extension = '.obj' ;
        Windows_path = strcat(MATLABpath, 'Windows/') ;
        Windows_rand48 = strcat(MATLABpath, 'Windows/rand48') ;
        cholmod_matlab = [cholmod_matlab {Windows_rand48}] ;
        include = [include ' -I' Windows_path] ;
    else
        obj_extension = '.o' ;
    end
    
    % compile each library source file
    cholmod_obj = '' ;
    
    source = [ordering_src config_src cholmod_src cholmod_matlab] ;
    if (have_metis)
        source = [metis_src source] ;
    end
    
    details = 0 ;
    kk = 0 ;
    
    %% -------------- Compile CHOLMOD objects from source code -------------- %%
    for f = source
        ff = f {1} ;
        if (isequal (ff, [metis_path '/GKlib/util']))
            % special case, since a file with the same name also exists in libmetis
            copyfile ([ff '.c'], 'GKlib_util.c', 'f') ;
            ff = 'GKlib_util' ;
            o = 'GKlib_util' ;
        elseif (isequal (ff, [metis_path '/GKlib/graph']))
            % special case, since a file with the same name also exist in libmetis
            copyfile ([ff '.c'], 'GKlib_graph.c', 'f') ;
            ff = 'GKlib_graph' ;
            o = 'GKlib_graph' ;
        else
            slash = strfind (ff, '/') ;
            if (isempty (slash))
                slash = 1 ;
            else
                slash = slash (end) + 1 ;
            end
            o = ff (slash:end) ;
        end
        cholmod_obj = [cholmod_obj  ' ' o obj_extension] ;
        if (bypass_cholmod == false)
            fprintf('\n\n  Making object file %s.o\n\n', o) ;
            s = sprintf ('mex %s -DDLONG -O %s -c %s.c', flags, include, ff) ;
            kk = do_cmd (s, kk, details) ;
        end
    end

    % Indicate whether or not cholmod has been compiled successfully
    if (bypass_cholmod == false)
        fprintf ('\nCHOLMOD successfully compiled\n') ;
    else
        fprintf ('\nWarning: Compilation of CHOLMOD bypassed\n') ;
    end

    %% ---------- Compile the PASA object and mex files ---------- %%
    % Used for printing details when compiling
    details = 0 ;
    % Used during compilation of objects
    kk = 0 ;

    %% ---------- Indicate include directories and source code ---------- %%
    % expand cholmod include directories to incorporate those of pasa
    include = [include ' -I. -I../Include -I../../SuiteOPTconfig'] ;
    % Include necessary SuiteOPT solvers
    include = [include ' -I../../CGDESCENT/Include'] ;
    include = [include ' -I../../NAPHEAP/Include'] ;
    include = [include ' -I../../PPROJ/Include'] ;
    % Include directories with prototypes for SUITEOPT matlab functions
    include = [include ' -I../../MATLAB/Include'] ;

    % list of suiteopt source files to include in mex compilation
    suiteopt_matlab_src = {...
             '../../MATLAB/Source/suiteopt_matlab', ...
             '../../MATLAB/Source/cg_descent_matlab', ...
             '../../MATLAB/Source/napheap_matlab', ...
             '../../MATLAB/Source/pproj_matlab', ...
             '../../MATLAB/Source/pasa_matlab'} ;
    
    % list of source files to include in mex compilation of pasa
    pproj_check_src = {'../../PPROJ/Check/pproj_checkA', ...
                 '../../PPROJ/Check/pproj_checkb', ...
                 '../../PPROJ/Check/pproj_check_AFT', ...
                 '../../PPROJ/Check/pproj_check_diag3', ...
                 '../../PPROJ/Check/pproj_check_line', ...
                 '../../PPROJ/Check/pproj_check_order', ...
                 '../../PPROJ/Check/pproj_checkc', ...
                 '../../PPROJ/Check/pproj_check_eqn5', ...
                 '../../PPROJ/Check/pproj_check_diag', ...
                 '../../PPROJ/Check/pproj_check_link', ...
                 '../../PPROJ/Check/pproj_check_AT', ...
                 '../../PPROJ/Check/pproj_check_const', ...
                 '../../PPROJ/Check/pproj_checkF', ...
                 '../../PPROJ/Check/pproj_check_minheap', ...
                 '../../PPROJ/Check/pproj_check_back', ...
                 '../../PPROJ/Check/pproj_checkD', ...
                 '../../PPROJ/Check/pproj_check_dual', ...
                 '../../PPROJ/Check/pproj_check_forward', ...
                 '../../PPROJ/Check/pproj_check_deriv', ...
                 '../../PPROJ/Check/pproj_check_modlist'} ;
    
    pproj_src = {'../../PPROJ/Source/pproj_init', ...
                 '../../PPROJ/Source/pproj_phase1', ...
                 '../../PPROJ/Source/pproj_hotchol', ...
                 '../../PPROJ/Source/pproj_coor_ascent', ...
                 '../../PPROJ/Source/pproj_dasa', ...
                 '../../PPROJ/Source/pproj_sparsa', ...
                 '../../PPROJ/Source/pproj_ssor0', ...
                 '../../PPROJ/Source/pproj_ssor1', ...
                 '../../PPROJ/Source/pproj_print', ...
                 '../../PPROJ/Source/pproj_default', ...
                 '../../PPROJ/Source/pproj'} ;

    cg_descent_src = {'../../CGDESCENT/Source/cg_default', ...
                      '../../CGDESCENT/Source/cg_print', ...
                      '../../CGDESCENT/Source/cg_util', ...
                      '../../CGDESCENT/Source/cg_descent'} ;
    
    napheap_src = {'../../NAPHEAP/Source/napheap_default', ...
                   '../../NAPHEAP/Source/napheap_print', ...
                   '../../NAPHEAP/Source/napheap', ...
                   '../../NAPHEAP/Source/napheap_check'} ;
    
    pasa_src = {'../Source/pasa', ...
                '../Source/pasa_default', ...
                '../Source/pasa_print'} ;
    
    %% ------------------- Required flags ------------------- %%
    % These flags are REQUIRED for the PASA mex function to compile
    % add '-DPASA_MATLAB' to indicate PASA
    flags = [flags ' -DPASA_MATLAB'] ;

    % add '-DSUITEOPT_MATLAB_OBJ' to indicate solver uses obj/grad/valgrad
    flags = [flags ' -DSUITEOPT_MATLAB_OBJ'] ;

    % add '-DSUITEOPT_MATLAB_HPROD' to indicate solver uses hprod
    flags = [flags ' -DSUITEOPT_MATLAB_HPROD'] ;

    % add '-DSUITEOPT_MATLAB_CGHPROD' to indicate solver uses cghprod
    flags = [flags ' -DSUITEOPT_MATLAB_CGHPROD'] ;

    % add '-DSUITEOPT_MATLAB_BOUND_CONSTRAINTS' to indicate bound constraints
    flags = [flags ' -DSUITEOPT_MATLAB_BOUND_CONSTRAINTS'] ;

    % add '-DSUITEOPT_MATLAB_POLYHEDRAL_CONSTRAINTS' indicate polyhedral constr
    flags = [flags ' -DSUITEOPT_MATLAB_POLYHEDRAL_CONSTRAINTS'] ;

    %% ------------------- Debugging flags ------------------- %%
    % add '-g' flag for debugging           
    %flags = [flags ' -g'] ; 
    
    % add '-v' flag for verbose mode           
    %flags = [flags ' -v'] ; 
    
    % add '-DNDEBUG' to turn off debugging
    flags = [flags ' -DNDEBUG'] ;
    
    % add '-DDEBUG_SUITEOPT_MEX' to turn on debugging for SuiteOPT matlab funcs
    %flags = [flags ' -DDEBUG_SUITEOPT_MEX'] ;

    % add '-DDEBUG_PASA_MEX' to turn on debugging for PPROJ MEX funcs
    %flags = [flags ' -DDEBUG_PASA_MEX'] ;
    
    %% ---------------- Compile objects from source code ---------------- %%
    % Start with cg_descent objects since this requires extra work
    source = [cg_descent_src] ;
    
    % Keep track of all object files compiled for later cleanup of directory
    pasa_obj = '' ;
    
    % --- Compiile cg_descent object with -DPASA flag and name pasa_cg_descent.o
    % Note: This is necessary since pasa requires the original version of
    % cg_descent for solving unconstrained problems and a special version of
    % cg_descent compiled with the -DPASA flag for use as the LCO in phase
    % 2 of PASA. mex gives a warning when trying to use the '-output' flag to
    % rename the object when compiling so we use a shell command to rename
    % the object compiled with the -DPASA flag to 'pasa_cg_descent.o' then
    % compile all of the cg_descent objects using the normal process
    % Append pasa_cg_descent object file name to pasa_obj list
    pasa_obj = [pasa_obj ' pasa_cg_descent' obj_extension] ;
    if (bypass_objects == false)
        % Compiile cg_descent object
        fprintf('\n\n  Making object file pasa_cg_descent.o\n\n', o) ;
        s = sprintf('mex %s -DDLONG -O -DPASA %s -c ../../CGDESCENT/Source/cg_descent.c', ...
                    flags, include) ;
        kk = do_cmd (s, kk, details) ;
        % Rename resulting object by prepending 'pasa_'
        s = sprintf('!mv cg_descent.o pasa_cg_descent.o', o, o) ;
        kk = do_cmd (s, kk, details) ;
    end

    % Compile cg_descent files without -DPASA flag 
    for f = source 
        ff = f {1} ;
        slash = strfind (ff, '/') ;
        if (isempty (slash))
            slash = 1 ;
        else
            slash = slash (end) + 1 ;
        end
        o = ff (slash:end) ;
        % Append cg_descent object file name to pasa_obj list
        pasa_obj = [pasa_obj ' ' o obj_extension] ;
        if (bypass_objects == false)
            % --- Compiile cg_descent objects without -DPASA flag
            fprintf('\n\n  Making object file %s.o\n\n', o) ;
            s = sprintf('mex %s -DDLONG -O %s -c %s.c', flags, include, ff) ;
            kk = do_cmd (s, kk, details) ;
        end
    end

    % Remaining objects to be compiled
    source = [suiteopt_matlab_src ...
              pproj_check_src ...
              pproj_src ...
              napheap_src ...
              pasa_src] ;

    % compile remaining object files with -DPASA flag
    for f = source 
        ff = f {1} ;
        slash = strfind (ff, '/') ;
        if (isempty (slash))
            slash = 1 ;
        else
            slash = slash (end) + 1 ;
        end
        o = ff (slash:end) ;
        pasa_obj = [pasa_obj ' ' o obj_extension] ;
        if (bypass_objects == false)
            fprintf('\n\n  Making object file %s.o\n\n', o) ;
            s = sprintf('mex %s -DDLONG -O -DPASA %s -c %s.c', ...
                                                          flags, include, ff) ;
            kk = do_cmd (s, kk, details) ;
        end
    end


    % Indicate whether or not SuiteOPT objects have been compiled successfully
    if (bypass_objects == false)
        fprintf ('\nPASA object files successfully compiled\n') ;
    else
        fprintf ('\nWarning: Compilation of PASA object files bypassed\n') ;
    end

    %% ---------------- Compile mex function(s) ---------------- %%
    % list of mex functions required in mex compilation of pasa
    pasa_mex_src = {'pasa'} ;

    % compile each mexFunction
    for f = pasa_mex_src
        fprintf('\n\n  Making mex function %s.mex\n\n', f{1}) ;
        s = sprintf('mex %s -DDLONG %s %s_mex.c %s %s %s -output %s', ...
                    flags, include, f{1}, cholmod_obj, pasa_obj, lapack, f{1}) ;
        kk = do_cmd (s, kk, details) ;
    end
    
    %% ---------------- Clean up and exit ---------------- %%
    % clean up object files created during installation
    if (bypass_cleanup == false)
        % remove CHOLMOD files, if they exist
        s = ['delete ' cholmod_obj] ;
        do_cmd (s, kk, details) ;
        % remove PASA files, if they exist
        s = ['delete ' pasa_obj] ;
        do_cmd (s, kk, details) ;
        % remove the renamed METIS files, if they exist
        if (exist ('GKlib_util.c', 'file'))
            delete ('GKlib_util.c') ;
        end
        if (exist ('GKlib_graph.c', 'file'))
            delete ('GKlib_graph.c') ;
        end
    end

    % Call pasa function to print information about pasa
    pasa ;
    
    %------------------------------------------------------------------------------
    % Function used in installation routine
    function kk = do_cmd (s, kk, details)
        %DO_CMD: evaluate a command, and either print it or print a "."
        if (details)
            fprintf ('%s\n', s) ;
        else
            if (mod (kk, 60) == 0)
                fprintf ('\n') ;
            end
            kk = kk + 1 ;
            fprintf ('.') ;
        end
        eval (s) ; 
    end

end
