opção javac para compilar todos os arquivos java em um determinado diretório recursivamente

127

Estou usando o compilador javac para compilar arquivos java no meu projeto. Os arquivos são distribuídos ao longo de vários pacotes como esta: com.vistas.util, com.vistas.converter, com.vistas.LineHelper, com.current.mdcontect.

Cada um desses pacotes possui vários arquivos java. Estou usando javac assim:

javac com/vistas/util/*.java com/vistas/converter/*.java
      com.vistas.LineHelper/*.java com/current/mdcontect/*.java

(em uma linha)

Em vez de fornecer tantos caminhos, como posso pedir ao compilador para compilar recursivamente todos os arquivos java do diretório com pai?

user496934
fonte
2
Você realmente deve dar uma olhada em ferramentas como Ant ou Maven.
Laurent Pireyn
Este post SO pode ser útil stackoverflow.com/questions/864630/...
Gopi

Respostas:

220

Eu também sugeriria usar algum tipo de ferramenta de construção ( Ant ou Maven , Ant já é sugerido e é mais fácil começar) ou um IDE que lida com a compilação (o Eclipse usa compilação incremental com estratégia de reconciliação, e você nem precisa pressione qualquer botão "Compilar" ).

Usando Javac

Se você precisar tentar algo para um projeto maior e não tiver nenhuma ferramenta de construção adequada por perto, sempre poderá usar um pequeno truque que javacoferece: os nomes de classe a serem compilados podem ser especificados em um arquivo. Você simplesmente precisa passar o nome do arquivo para javaccom o @prefixo.

Se você pode criar uma lista de todos os *.javaarquivos em seu projeto, é fácil:

# Linux / MacOS
$ find -name "*.java" > sources.txt
$ javac @sources.txt

:: Windows
> dir /s /B *.java > sources.txt
> javac @sources.txt
  • A vantagem é que é uma solução rápida e fácil.
  • A desvantagem é que você precisa regenerar o sources.txtarquivo sempre que criar uma nova fonte ou renomear um arquivo existente, o que é uma tarefa fácil de esquecer (portanto sujeita a erros) e cansativa.

Usando uma ferramenta de construção

A longo prazo, é melhor usar uma ferramenta projetada para criar software.

Usando Ant

Se você criar um build.xmlarquivo simples que descreve como criar o software:

<project default="compile">
    <target name="compile">
        <mkdir dir="bin"/>
        <javac srcdir="src" destdir="bin"/>
    </target>
</project>

você pode compilar o software inteiro executando o seguinte comando:

$ ant
  • A vantagem é que você está usando uma ferramenta de construção padrão fácil de estender.
  • A desvantagem é que você precisa baixar, configurar e aprender uma ferramenta adicional. Observe que a maioria dos IDEs (como NetBeans e Eclipse) oferece ótimo suporte para gravar arquivos de construção, para que você não precise baixar nada neste caso.

Usando o Maven

O Maven não é tão trivial de configurar e trabalhar, mas aprendê-lo paga bem. Aqui está um ótimo tutorial para iniciar um projeto em 5 minutos .

  • Sua principal vantagem (para mim) é que ele também lida com dependências, assim você não precisará baixar mais arquivos Jar e gerenciá-los manualmente, e achei mais útil para criar, empacotar e testar projetos maiores.
  • A desvantagem é que ele possui uma curva de aprendizado acentuada, e se os plugins do Maven gostam de suprimir erros :-) Outra coisa é que muitas ferramentas também funcionam com os repositórios do Maven (como Sbt for Scala, Ivy for Ant, Graddle for Groovy) .

Usando um IDE

Agora, o que poderia aumentar sua produtividade de desenvolvimento. Existem algumas alternativas de código aberto (como Eclipse e NetBeans , prefiro a primeira) e até mesmo comerciais (como IntelliJ ) que são bastante populares e poderosas.

Eles podem gerenciar a construção do projeto em segundo plano, para que você não precise lidar com todo o material da linha de comando. No entanto, sempre é útil se você souber o que realmente acontece em segundo plano, para que possa caçar erros ocasionais como um ClassNotFoundException.

Uma nota adicional

Para projetos maiores, é sempre recomendável usar um IDE e uma ferramenta de construção. O primeiro aumenta sua produtividade, enquanto o último possibilita o uso de IDEs diferentes no projeto (por exemplo, o Maven pode gerar descritores de projeto do Eclipse com um simples mvn eclipse:eclipsecomando). Além disso, é fácil apresentar um projeto que pode ser testado / construído com um comando de linha única para novos colegas e em um servidor de integração contínua, por exemplo. Pedaco de bolo :-)

rlegendi
fonte
4
Ao usar javac, seria melhor especificar um diretório de saída. find -name "*.java" > sources.txt && javac -d bin @sources.txt. Caso contrário, os arquivos * .class são salvos no diretório em que as fontes estão.
Maksim Dmitriev
1
Totalmente verdade. Embora, na minha opinião, se alguém apenas comece a brincar javac, o conceito de CLASSPATHcomo executar código java, como lidar com pacotes, que deve ser a pasta raiz para execução etc. geralmente não são claros. Assim, eu omiti o dir de saída. Enfim, obrigado pela sugestão!
Rlegendi
6
Para usuários de mac que se deparam com isso, o findcomando é: find . -name "*.java" > sources.txt(observe o .)
MrDuk 21/09/15
@MrDuk O que significa adicionar o "." Faz? É para pesquisar no diretório atual?
Brady Sheehan
@BradySheehan começará a pesquisar a partir do caminho especificado. "." significa começar do dicionário atual. Note que você tem de especificar um caminho para find (no OS X)
Kris
39
find . -name "*.java" -print | xargs javac 

Meio brutal, mas funciona como o inferno. (Use apenas em pequenos programas, não é absolutamente eficiente)

Matthieu Riegler
fonte
1
Se você usar este considerar find ... -print0e xargs -0 ...em vez para não quebrar em espaços em nomes de arquivos
sapht
29

Se o seu shell o suportar, algo assim funcionaria?

javac com/**/*.java 

Se o seu shell não suportar **, então talvez

javac com/*/*/*.java

funciona (para todos os pacotes com 3 componentes - adapte-se para mais ou menos).

phtrivier
fonte
Tentei usar isso em prompt de comando no Windows 10. Alguém pode confirmar se ele funciona no Windows 10 ou se eu estou fazendo errado agradar
Dan
26

No caso usual em que você deseja compilar todo o seu projeto, você pode simplesmente fornecer o javac com sua classe principal e deixá-lo compilar todas as dependências necessárias:

javac -sourcepath . path/to/Main.java

freaker
fonte
Método muito simples, não depende de arquivos extras
linquize
Este é o melhor e mais simples para as pessoas que não tem muito tempo para aprender Ant (como eu)
Hamza Abbad
Infelizmente, é preguiçoso. Se você não tocar Main.java, o que provavelmente não aconteceria depois de criar seu segundo arquivo, nada mais será compilado.
Tom Hawtin - defina
Também não funciona bem aqui. Algumas dependências não são recompiladas, apesar de terem sido alteradas. @ TomHawtin-tackline Eu tentei tocar antes no principal, mas nada. Talvez seja necessário tocar em tudo. Tipo de estranho embora.
mmm
4

javac -cp "jar_path/*" $(find . -name '*.java')

(Prefiro não usar xargs porque ele pode ser dividido e executado javac várias vezes, cada um com um subconjunto de arquivos java, alguns dos quais podem importar outros não especificados na mesma linha de comando javac)

Se você tem um ponto de entrada App.java, o caminho do freaker com -sourcepath é melhor. Ele compila todos os outros arquivos java necessários, seguindo as dependências de importação. por exemplo:

javac -cp "jar_path/*" -sourcepath src/ src/com/companyname/modulename/App.java

Você também pode especificar um dir classe-arquivo de destino: -d target/.

Curtis Yallop
fonte
3

Aconselho você a aprender a usar o ant , que é muito adequado para esta tarefa e é muito fácil de entender e bem documentado.

Você apenas teria que definir um destino como este no arquivo build.xml:

<target name="compile">
    <javac srcdir="your/source/directory"
           destdir="your/output/directory"
           classpath="xyz.jar" />
</target>
JB Nizet
fonte
2

Estou apenas usando make com um makefile simples que se parece com isso:

JAVAC = javac -Xlint:unchecked
sources = $(shell find . -type f -name '*.java')
classes = $(sources:.java=.class)

all : $(classes)

clean :
        rm -f $(classes)

%.class : %.java
        $(JAVAC) $<

Ele compila as fontes uma por vez e apenas recompila se necessário.

Edward Doolittle
fonte
1

O comando javac não segue um processo de compilação recursiva; portanto, você deve especificar cada diretório ao executar o comando ou fornecer um arquivo de texto com os diretórios que deseja incluir:

javac -classpath "${CLASSPATH}" @java_sources.txt
gvalenncia
fonte
0

Eu tenho usado isso em um projeto Xcode JNI para construir recursivamente minhas classes de teste:

find ${PROJECT_DIR} -name "*.java" -print | xargs javac -g -classpath ${BUILT_PRODUCTS_DIR} -d ${BUILT_PRODUCTS_DIR}
bispo
fonte