! $Id: cross_matrix.F 1458 2014-02-03 15:01:25Z gcambon $ ! !====================================================================== ! CROCO is a branch of ROMS developped at IRD and INRIA, in France ! The two other branches from UCLA (Shchepetkin et al) ! and Rutgers University (Arango et al) are under MIT/X style license. ! CROCO specific routines (nesting) are under CeCILL-C license. ! ! CROCO website : http://www.croco-ocean.org !====================================================================== ! ! This is "cross_matrix": analyzer of dependencies to build ! table of dependencies "Make.depend" !------------------------------------------------------------------ ! Usage: !-------- cross_matrix list_of_files ! for example ! cross_matrix *.F ! or ! cross_matrix *.F *.h ! or ! cross_matrix $(SRCS) inside a makefile ! ! Algorithm: !----------- ! cross_matrix reads all files from the list arguments it is given, ! and searches for the CPP command #include. If #include commands ! are found, in interprets names within the "..." as new files to be ! open and searched for #include inside it and so on. ! ! cross_matrix investigates chained include statements, for example, ! if file1 contains statement #include "file2", and file2 contains ! statement #include "file3", therefore file3 will be included into ! list of dependencies of "file1" ! ! Optionally, files which are not in the list of arguments AND ! which are not in the present working directory can be excluded ! from the list of dependencies (CPP switch EXCLUDE). A warning ! message will be issued about each file excluded from analysis. ! #define EXCLUDE implicit none integer max_name_size, max_names, max_string_size, input,iout parameter (max_name_size=62, max_names=956, max_string_size=300, & input=11, iout=12) character*300 fname(max_names) logical ismodule(max_names,max_names) character*300 modname character*4 sufname character string*300, quote*1, double_quote*1, backslash*1 integer nsize(max_names), size, lines, nmax, n_disc, n_excl, & last_arg, iargc, iocheck, i,j,k,n, & my_iostat logical matrix(max_names,max_names), new_name, not_end_of_file character ctoupper,tab tab=char(9) last_arg=iargc() if (last_arg.eq.0) then write(*,*) 'ERROR IN cross_matrix: NO FILE NAMES ARE GIVEN' stop endif ismodule(:,:)=.false. write(*,'(/1x,A,1x,A/)') 'This is CROSS_MATRIX: Creating', & 'new version of Make.depend.' quote=char(39) ! double_quote=char(34) ! Reset everything: backslash=char(92) ! lines=0 ! <-- line counter all files altogether n_disc=0 ! <-- counter of newly discovered files n_excl=0 ! <-- counter of excluded files do j=1,max_names ! nsize(j)=0 ! <-- array of sizes of filenames do i=1,max_name_size ! fname(j)(i:i)=' ' ! <-- character array of filenames enddo ! do i=1,max_names ! matrix(i,j)=.false. ! <-- matrix of dependencies: enddo ! enddo ! Note: matrix(i,j)=.eq..true. means ! that file j depends on i. do n=1,last_arg call getarg(n,fname(n)) i=max_name_size+1 1 i=i-1 if (fname(n)(i:i).eq.' ' .and. i.gt.1) goto 1 nsize(n)=i enddo nmax=last_arg open(unit=iout, file='Make.depend', form='formatted') write(iout,'(3(A,1x,A/),A/A/A/A/A/A)') & '# Make.depend: list of dependencies generated by', & 'cross_matrix.', '# WARNING: THIS IS A MACHINE', & 'GENERATED FILE: DO NOT EDIT !!!!!', '# To create', & 'or update this file use commands:', '#', & '# cross_matrix *.F', '# or', & '# cross_matrix *.F *.h', '# or', & '# make depend' n=0 2 n=n+1 not_end_of_file=.true. IF (n.GT.nmax) GOTO 29 IF (fname(n)(nsize(n)-3:nsize(n)).EQ.'.mod') goto 2 open(unit=input, file=fname(n), form='formatted', & status='old', err=3) goto 4 3 continue #ifdef EXCLUDE n_excl=n_excl+1 write(iout,'(A/A,2x,A/A)') '#', & '# WARNING: File is not found:',fname(n)(1:nsize(n)), & '# This file is excluded from the dependency list.' do i=1,nsize(n) fname(n)(i:i)=' ' enddo nsize(n)=0 goto 2 #endif 4 string(1:1)=' ' read(input,'(A)',iostat=iocheck,end=5) string lines=lines+1 if (iocheck.eq.0 .and. string(1:1).ne.'#') goto 19 goto 6 ! Search for word include, 5 not_end_of_file=.false. ! then search for double 6 i=2 ! quotation marks, then 7 if (string(i:i).ne.'i') then ! read portion of the i=i+1 ! string between "..."s. if (i.lt.max_string_size) goto 7 elseif (string(i:i+6) .eq. 'include') then i=i+7 8 if (string(i:i).eq.double_quote) then j=i+2 9 if (string(j:j).eq.double_quote) then size=j-i-1 ! Presume that the newly new_name=.true. ! encountered name does do k=1,nmax ! not exist in catalog. if (size .eq. nsize(k)) then if (string(i+1:j-1) .eq. fname(k)(1:size)) then new_name=.false. ! matrix(k,n)=.true. ! Then test the new name endif ! against those already in endif ! catalog. If matches were enddo ! found, reject it as a if (new_name) then ! new name and make entry n_disc=n_disc+1 ! in dependency in matrix. nmax=nmax+1 ! Record the new name and matrix(nmax,n)=.true. ! its size into catalog, nsize(nmax)=size ! if it was not rejected. fname(nmax)(1:size)=string(i+1:j-1) do i=size+1,max_name_size fname(nmax)(i:i)=' ' enddo endif elseif (j.lt.max_string_size) then j=j+1 goto 9 endif elseif (i.lt.max_string_size) then i=i+1 goto 8 endif endif 19 continue if (iocheck.eq.0 .and. & ((string(1:1).ne.' ').AND. & (string(1:1).ne.tab))) goto 4 i=2 17 if ((string(i:i).eq.' ').OR.(string(i:i).eq.tab)) then i=i+1 if (i.lt.max_string_size) goto 17 elseif ((string(i:i+3) .eq. 'USE ').or. & (string(i:i+3) .eq. 'use ')) then sufname=string(i:i+3) i=i+4 j=i 18 j=j+1 if ((string(j:j).EQ.' ').or.(string(j:j).EQ.tab)) then j=j-1 size=j-i+1 do k=1,size ! modname(k:k)=ctoupper(string(i+k-1:i+k-1)) modname(k:k)=string(i+k-1:i+k-1) end do modname(size+1:size+4)='.F90' size=size+4 open(unit=125, file=modname(1:size), form='formatted', & status='old', iostat=my_iostat) close(125) if(my_iostat /= 0) then size=size-4 modname(size+1:size+2)='.F' size=size+2 endif new_name=.true. ! encountered name does do k=1,nmax ! not exist in catalog. if (size .eq. nsize(k)) then if (modname(1:size) .eq. fname(k)(1:size)) then new_name=.false. ! matrix(k,n)=.true. ! Then test the new name ismodule(k,n)=.true. endif ! against those already in endif ! catalog. If matches were enddo ! found, reject it as a if (new_name) then ! new name and make entry n_disc=n_disc+1 ! in dependency in matrix. nmax=nmax+1 ! Record the new name and matrix(nmax,n)=.true. ! its size into catalog, nsize(nmax)=size ! if it was not rejected. fname(nmax)(1:size)=modname(1:size) ismodule(nmax,n)=.true. do i=size+1,max_name_size fname(nmax)(i:i)=' ' enddo endif elseif (j.lt.max_string_size) then goto 18 end if end if if (not_end_of_file) goto 4 close (unit=input) if (n.lt.nmax) goto 2 29 continue i=0 ! Investigate possible secondary 10 do n=1,nmax ! dependencies. This is equivalent do k=1,nmax ! to operation of logical addition: if (matrix(k,n)) then ! do j=1,nmax ! if if (matrix(j,k)) then ! file1 depends on file2 matrix(j,n)=.true. if (ismodule(j,k)) ismodule(j,n)=.true. endif ! and enddo ! file2 depends on file3 endif ! then enddo ! file1 depends on file3 enddo ! j=0 ! This is an iterative do n=1,nmax ! procedure, since staged do k=1,nmax ! include statements are if (matrix(k,n)) j=j+1 ! possible. The number of .true. enddo ! elements in the matrix grows enddo ! when new dependencies are if (i.ne.j) then ! discovered. The procedure i=j ! repeats itself until the next goto 10 ! iteration does not discover endif ! any new dependencies. ! ! Report statistics of the files: ! write(iout,'(A/A,5x,I4/A/A,18x,I4/A/A,1x,I4)') '#', & '# Number of files given for dependency analysis:', last_arg, & '#', '# Number of newly discovered files:', n_disc, '#', & '# Number of files excluded from dependency analysis:',n_excl write(iout,'(A/A,3x,I4/A/A,9x,I6/A)') '#', & '# Total number of files analyzed for dependencies:', nmax, & '#', '# Total number of code lines in all files:', lines, '#' ! ! Generate list of dependencies. Two styles are supported, both ! work just fine. If XCOMM_FORMAT is defined, the style of the list ! is similar to that of makefiles generated by imake utility ! recommended by $XConsortium. In this case the target file name ! and the column separator ':' are repeated in all lines which ! correspond to the target dependencies, and its name is also ! repeated one time more wit no characters after ':'. ! If XCOMM_FORMAT is NOT defined, the target file name and the ! column separator ':' are not repeated, while backslach symbol is ! used in the end of each line, if the line needs to be continued ! on the next line. do n=1,last_arg !!! nmax if (nsize(n).gt.0) then #define XCOMM_FORMAT #ifdef XCOMM_FORMAT write(iout,'(A1)') '#' k=0 11 i=nsize(n) string(1:i)=fname(n)(1:i) if (string(i-1:i).eq.'.F') string(i:i)='o' if (string(i-3:i).eq.'.F90') string(i-2:i)='o' i=i+1 string(i:i)=':' 12 i=i+1 string(i:i)=' ' if (k.eq.0) then if (fname(n)(nsize(n)-1:nsize(n)).eq.'.F') then string(i+1:i+nsize(n))=fname(n)(1:nsize(n)) i=i+nsize(n)+1 string(i:i)=' ' endif if (fname(n)(nsize(n)-3:nsize(n)).eq.'.F90') then string(i+1:i+nsize(n))=fname(n)(1:nsize(n)) i=i+nsize(n)+1 string(i:i)=' ' endif endif 13 k=k+1 if (matrix(k,n)) then if (i+nsize(k).lt.max_string_size) then string(i+1:i+nsize(k))=fname(k)(1:nsize(k)) if(ismodule(k,n))then if(string(i+nsize(k)-1:i+nsize(k)).eq.'.F') then string(i+nsize(k)-1:i+nsize(k))= '.o' endif if(string(i+nsize(k)-3:i+nsize(k)).eq.'.F90') then string(i+nsize(k)-3:i+nsize(k))='.o ' endif endif i=i+nsize(k) goto 12 else write(iout,'(A)') string(1:i) goto 11 endif elseif (k.lt.nmax) then goto 13 else write(iout,'(A)') string(1:i) if (i.gt.nsize(n)+2) then write(iout,'(A)') string(1:nsize(n)+1) endif endif #else if (n.eq.1 .or. j.gt.0) write(iout,*) j=0 i=nsize(n) string(1:i)=fname(n)(1:i) if (fname(n)(nsize(n)-1:nsize(n)).eq.'.F') then string(i:i)='o' i=i+1 string(i:i)=':' j=1 i=i+1 string(i:i)=' ' string(i+1:i+nsize(n))=fname(n)(1:nsize(n)) i=i+nsize(n) else ! Do not print dependency line, i=i+1 ! if the file oes not depend on string(i:i)=':' ! anything, except itself. To endif ! detect trivial dependencies, k=0 ! set j=0, then set it to j=1, 14 k=k+1 ! when dependency is detected. if (matrix(k,n)) then ! Do not print, if j remains 0. j=1 15 if (i+nsize(k).lt.max_string_size-2) then i=i+1 string(i:i)=' ' string(i+1:i+nsize(k))=fname(k)(1:nsize(k)) i=i+nsize(k) else i=i+1 string(i:i)=backslash write(iout,'(A)') string(1:i) i=0 goto 15 endif endif if (k.lt.nmax) goto 14 if (j.gt.0) write(iout,'(A)') string(1:i) #endif endif enddo close (iout) stop end character function ctoupper(c) character c character temp temp=c IF ((ichar(c).GE.ichar('a')).AND.(ichar(c).LE.ichar('z'))) & temp=char(ichar(c)+ichar('A')-ichar('a')) ctoupper=temp return end