function cholmod_make (metis_path)
%CHOLMOD_MAKE compiles the CHOLMOD mexFunctions
%
% Example:
%   cholmod_make
%
% CHOLMOD relies on AMD, COLAMD, CCOLAMD, CAMD, and METIS for its
% ordering options.
%
% All but METIS are distributed with CHOLMOD.  To compile CHOLMOD
% to use METIS you must first place a copy of the metis-4.0
% directory (METIS version 4.0.1) in same directory that contains
% the AMD, COLAMD, CCOLAMD, and CHOLMOD directories.  Next, type
%
%   cholmod_make
%
% in the MATLAB command window.  Alternatively, use this command:
%
%   cholmod_make ('path to your copy of metis-4.0 here') ;
%
% See http://www-users.cs.umn.edu/~karypis/metis for a copy of
% METIS 4.0.1.  If you do not have METIS, use either of the following:
%
%   cholmod_make ('')
%   cholmod_make ('no metis')
%
% You must type the cholmod_make command while in the
% CHOLMOD/MATLAB directory.
%
% See also cholmod2

%   Copyright 2006, Timothy A. Davis
%   http://www.cise.ufl.edu/research/sparse

help cholmod_make

if (~isempty (strfind (computer, '64')))
    error ('64-bit version not yet supported') ;
end

try
    % determine if this is MATLAB 7.0 or greater
    v = str2double (strtok (version, '.')) ;
    old = (isempty (v) | v < 7) ;
catch
    % if the above failed, this must be an old version of MATLAB
    old = 1 ;
end

if (ispc)

    %---------------------------------------------------------------------------
    % edit this definition, if necessary:
    lapack = 'libmwlapack.lib' ;
    %---------------------------------------------------------------------------

    fprintf ('Using LAPACK library:\n%s\n', lapack) ;
    fprintf ('If this does not work, edit cholmod_make.m and\n') ;
    fprintf ('modify the definition of lapack=''...''.\n') ;
else
    % For other systems, mex can find lapack on its own.
    lapack = '' ;
end

fprintf ('Now compiling CHOLMOD:\n') ;

include = '-I. -I../../AMD/Include -I../../AMD/Source -I../../COLAMD -I../../CCOLAMD -I../../CAMD/Include -I../Include -I../../UFconfig' ;

if (old)
    % do not attempt to compile CHOLMOD with large file support
    include = [include ' -DNLARGEFILE'] ;
elseif (~ispc)
    % Linux/Unix require these flags for large file support
    include = [include ' -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE'] ;
end

% Determine the METIS path, and whether or not METIS is available
if (nargin == 0)
    metis_path = '../../metis-4.0' ;
end
if (strcmp (metis_path, 'no metis'))
    metis_path = '' ;
end
have_metis = (~isempty (metis_path)) ;

% fix the METIS 4.0.1 rename.h file
if (have_metis)
    f = fopen ('rename.h', 'w') ;
    if (f == -1)
        error ('unable to create rename.h in current directory') ;
    end
    fprintf (f, '/* do not edit this file; generated by cholmod_make */\n') ;
    fprintf (f, '#undef log2\n') ;
    fprintf (f, '#include "%s/Lib/rename.h"\n', metis_path) ;
    fprintf (f, '#undef log2\n') ;
    fprintf (f, '#define log2 METIS__log2\n') ;
    fprintf (f, '#include "mex.h"\n') ;
    fprintf (f, '#define malloc mxMalloc\n') ;
    fprintf (f, '#define free mxFree\n') ;
    fprintf (f, '#define calloc mxCalloc\n') ;
    fprintf (f, '#define realloc mxRealloc\n') ;
    fclose (f) ;
    include = [include ' -I' metis_path '/Lib'] ;
else
    fprintf ('Compiling CHOLMOD without METIS\n') ;
    include = ['-DNPARTITION ' include] ;
end

include = strrep (include, '/', filesep) ;

amd_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_src = { ...
    '../../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_src = {
    '../../COLAMD/colamd', ...
    '../../COLAMD/colamd_global' } ;

ccolamd_src = {
    '../../CCOLAMD/ccolamd', ...
    '../../CCOLAMD/ccolamd_global' } ;

metis_src = {
    'Lib/balance', ...
    'Lib/bucketsort', ...
    'Lib/ccgraph', ...
    'Lib/coarsen', ...
    'Lib/compress', ...
    'Lib/debug', ...
    'Lib/estmem', ...
    'Lib/fm', ...
    'Lib/fortran', ...
    'Lib/frename', ...
    'Lib/graph', ...
    'Lib/initpart', ...
    'Lib/kmetis', ...
    'Lib/kvmetis', ...
    'Lib/kwayfm', ...
    'Lib/kwayrefine', ...
    'Lib/kwayvolfm', ...
    'Lib/kwayvolrefine', ...
    'Lib/match', ...
    'Lib/mbalance2', ...
    'Lib/mbalance', ...
    'Lib/mcoarsen', ...
    'Lib/memory', ...
    'Lib/mesh', ...
    'Lib/meshpart', ...
    'Lib/mfm2', ...
    'Lib/mfm', ...
    'Lib/mincover', ...
    'Lib/minitpart2', ...
    'Lib/minitpart', ...
    'Lib/mkmetis', ...
    'Lib/mkwayfmh', ...
    'Lib/mkwayrefine', ...
    'Lib/mmatch', ...
    'Lib/mmd', ...
    'Lib/mpmetis', ...
    'Lib/mrefine2', ...
    'Lib/mrefine', ...
    'Lib/mutil', ...
    'Lib/myqsort', ...
    'Lib/ometis', ...
    'Lib/parmetis', ...
    'Lib/pmetis', ...
    'Lib/pqueue', ...
    'Lib/refine', ...
    'Lib/separator', ...
    'Lib/sfm', ...
    'Lib/srefine', ...
    'Lib/stat', ...
    'Lib/subdomains', ...
    'Lib/timing', ...
    'Lib/util' } ;

for i = 1:length (metis_src)
    metis_src {i} = [metis_path '/' metis_src{i}] ;
end

cholmod_matlab = { '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' } ;

cholmod_mex_src = { ...
    'analyze', ...
    'bisect', ...
    'chol2', ...
    'cholmod2', ...
    'etree2', ...
    'lchol', ...
    'ldlchol', ...
    'ldlsolve', ...
    'ldlupdate', ...
    'metis', ...
    'spsym', ...
    'nesdis', ...
    'septree', ...
    'resymbol', ...
    'sdmult', ...
    'sparse2', ...
    'symbfact2', ...
    'mread', ...
    'mwrite' } ;

if (ispc)
    % Windows does not have drand48 and srand48, required by METIS.  Use
    % drand48 and srand48 in CHOLMOD/MATLAB/Windows/rand48.c instead.
    obj_extension = '.obj' ;
    cholmod_matlab = [cholmod_matlab {'Windows/rand48'}] ;
    include = [include ' -IWindows'] ;
else
    obj_extension = '.o' ;
end

% compile each library source file
obj = '' ;
k = 0 ;

source = [amd_src colamd_src ccolamd_src camd_src cholmod_src cholmod_matlab] ;
if (have_metis)
    source = [metis_src source] ;
end

for f = source
    ff = strrep (f {1}, '/', filesep) ;
    slash = strfind (ff, filesep) ;
    if (isempty (slash))
        slash = 1 ;
    else
        slash = slash (end) + 1 ;
    end
    o = ff (slash:end) ;
    obj = [obj  ' ' o obj_extension] ;					    %#ok
    s = sprintf ('mex -O %s -c %s.c', include, ff);
    % fprintf ('.') ;
    fprintf ('%s\n', s) ;
    k = k + 1 ;
    if (mod (k,50) == 0)
        fprintf ('\n') ;
    end
    eval (s) ;
end

% compile each mexFunction
for f = cholmod_mex_src
    s = sprintf ('mex -O %s %s.c', include, f{1}) ;
    s = [s obj ' ' lapack] ;						    %#ok
    % fprintf ('.') ;
    fprintf ('%s\n', s) ;
    k = k + 1 ;
    if (mod (k,50) == 0)
        fprintf ('\n') ;
    end
    eval (s) ;
end

% clean up
eval (['delete ' obj]) ;

fprintf ('\nNow compiling the AMD, COLAMD, CCOLAMD, and CAMD mexFunctions:\n') ;
cholmod_path = pwd ;
addpath (cholmod_path)

cd ../../AMD/MATLAB
amd_make
amd_path = pwd ;
addpath (amd_path)

cd ../../COLAMD
colamd_make
colamd_path = pwd ;
addpath (colamd_path)

cd ../CCOLAMD
ccolamd_make
ccolamd_path = pwd ;
addpath (ccolamd_path)

cd ../CAMD/MATLAB
camd_make
camd_path = pwd ;
addpath (camd_path)

cd (cholmod_path)

fprintf ('\nThe following paths have been added.  You may wish to add them\n') ;
fprintf ('permanently, using the MATLAB pathtool command.\n') ;
fprintf ('%s\n', cholmod_path) ;
fprintf ('%s\n', amd_path) ;
fprintf ('%s\n', colamd_path) ;
fprintf ('%s\n', ccolamd_path) ;
fprintf ('%s\n', camd_path) ;

fprintf ('\nTo try your new mexFunctions, cut-and-paste this command:\n') ;
fprintf ('amd_demo, colamd_demo, ccolamd_demo, camd_demo, graph_demo, cholmod_demo\n') ;
