Repository: mesonbuild/meson

Issue:
custom_target exe-wrapper data filename always changes on regen
I have custom target with LONG command line (around 500 files at once)
Simplified project:

[classpath.zip](https://www.dropbox.com/s/nsh2y46e6opqrw1/classpath.zip)
```
project('avian', ['cpp'])

subdir('classpath')

javac = find_program('javac')

classpath_classes = custom_target('classpath_classes',
  input: classpath_java_sources,
  output: 'classpath_classes',
  capture: true,
  command: [javac,
    '-encoding', 'UTF-8',
    '-source', '1.6', # JAVA_VERSION,
    '-target', '1.6', # JAVA_VERSION,
    '-d', meson.current_build_dir() + '/classpath',
    '-bootclasspath', meson.current_build_dir() + '/classpath',
    '@INPUT@'
  ],
)
```

Commands:
```
$ mkdir build
$ meson build
$ ninja -C build -d explain classpath_classes
```
Build success.
Next time:
```
$ ninja -C build -d explain classpath_classes
ninja: Entering directory `build'
ninja: no work to do.
```
But:
```
$ touch meson.build
$ ninja -C build -d explain classpath_classes
ninja: Entering directory `build'
ninja explain: output build.ninja older than most recent input ../meson.build (501180038 vs 501180064)
[0/1] Regenerating build files
The Meson build system
Version: 0.36.0
Source dir: F:\avian\classpath
Build dir: F:\avian\classpath\build
Build type: native build
Project name: avian
Native cpp compiler: c++ (gcc 6.2.0)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Program javac found: YES (C:\Program Files\Java\jdk1.8.0_111\bin\javac.EXE)
Build targets in project: 1
ninja explain: command line changed for classpath_classes
```

Where is command line changed?



Discussion:
```
project('avian', ['cpp'])
subdir('classpath')
javac = find_program('javac')
```

You should not need to do this, we have support for compiling Java (though, admittably, it is not as polished as other languages).

> Program javac found: YES (C:\Program Files\Java\jdk1.8.0_111\bin\javac.EXE)
> Build targets in project: 1
> ninja explain: command line changed for classpath_classes
> Where is command line changed?

If you run Ninja immediately after this, does it recompile anything or just report that no work is to be done.

If it does nor recompile anything then this is probably a case of Ninja getting confused by the fact that it gets regenerated. If it does recompile something, please look up what the command to execute would be (open build.ninja and search for it) both before and after doing the touch && ninja command.

> You  should not need to do this, we have support for compiling Java (though, admittably, it is not as polished as other languages).

I do really need this - first, it is only one target in c/cpp (mostly) project, second - it need to be done in a single command. Java jar taget handles source files one  by one - it's fine for incremental builds, but not in this case. And jar target even does not support something like `java_args:` parameter as for other languages.

And - this is irrelevant in this case, it could be any other target with very long command line.
Question is - why after reconfiguration of meson this target  is rebuit, and similar targets with short command line are not rebuilt?

> Question is - why after reconfiguration of meson this target is rebuit, and similar targets with short command line are not rebuilt?

In order to answer that I need the command lines from the Ninja file as described in the previous comment.

build.ninja:

```
# This is the build file for project "avian"
# It is autogenerated by the Meson build system.
# Do not edit by hand.

ninja_required_version = 1.5.1

# Rules for compiling.

rule cpp_COMPILER
 command = c++ @$out.rsp
 rspfile = $out.rsp
 rspfile_content =  $ARGS "-MMD" "-MQ" $out "-MF" "$DEPFILE" -o $out -c $in
 deps = gcc
 depfile = $DEPFILE
 description = Compiling cpp object $out

rule cpp_PCH
 command = c++  $ARGS "-MMD" "-MQ" $out "-MF" "$DEPFILE" -o $out -c $in
 deps = gcc
 depfile = $DEPFILE
 description = Precompiling header $in


# Rules for linking.

rule STATIC_LINKER
 command = ar @$out.rsp
 rspfile = $out.rsp
 rspfile_content = $LINK_ARGS $out $in
 description = Static linking library $out

rule cpp_LINKER
 command = c++ @$out.rsp
 rspfile = $out.rsp
 rspfile_content =  $ARGS  -o $out $in $LINK_ARGS $aliasing
 description = Linking target $out

rule SHSYM
 command = "c$:\program$ files$ (x86)\python35-32\python.exe" "C:\Program Files (x86)\Python35-32\Scripts\meson.PY" --internal symbolextractor $in $out $CROSS
 restat = 1
 description = Generating symbol file $out.

# Other rules

rule CUSTOM_COMMAND
 command = $COMMAND
 description = $DESC
 restat = 1

rule CUSTOM_COMMAND_DEP
 command = $COMMAND
 description = $DESC
 deps = gcc
 depfile = $DEPFILE
 restat = 1

rule REGENERATE_BUILD
 command = "c$:\program$ files$ (x86)\python35-32\python.exe" "C$:\Program$ Files$ (x86)\Python35-32\Scripts\meson.PY" --internal regenerate "F$:\avian\classpath" "F$:\avian\classpath\build" --backend ninja
 description = Regenerating build files
 generator = 1


# Phony build target, always out of date
build PHONY: phony

# Build rules for targets

build classpath_classes: CUSTOM_COMMAND ../classpath/avian/Addendum.java ../classpath/avian/AnnotationInvocationHandler.java ../classpath/avian/Assembler.java ../classpath/avian/Atomic.java ../classpath/avian/avianvmresource/Handler.java ../classpath/avian/Callback.java ../classpath/avian/Cell.java ../classpath/avian/ClassAddendum.java ../classpath/avian/Classes.java ../classpath/avian/Code.java ../classpath/avian/ConstantPool.java ../classpath/avian/Continuations.java ../classpath/avian/Data.java ../classpath/avian/FieldAddendum.java ../classpath/avian/file/Handler.java ../classpath/avian/FormatString.java ../classpath/avian/Function.java ../classpath/avian/http/Handler.java ../classpath/avian/IncompatibleContinuationException.java ../classpath/avian/InnerClassReference.java ../classpath/avian/Iso88591.java ../classpath/avian/jar/Handler.java ../classpath/avian/LegacyObjectInputStream.java ../classpath/avian/LegacyObjectOutputStream.java ../classpath/avian/Machine.java ../classpath/avian/MethodAddendum.java ../classpath/avian/Pair.java ../classpath/avian/PersistentSet.java ../classpath/avian/Singleton.java ../classpath/avian/Stream.java ../classpath/avian/SystemClassLoader.java ../classpath/avian/Traces.java ../classpath/avian/Utf8.java ../classpath/avian/VMClass.java ../classpath/avian/VMField.java ../classpath/avian/VMMethod.java ../classpath/dalvik/system/BaseDexClassLoader.java ../classpath/java/io/BufferedInputStream.java ../classpath/java/io/BufferedOutputStream.java ../classpath/java/io/BufferedReader.java ../classpath/java/io/BufferedWriter.java ../classpath/java/io/ByteArrayInputStream.java ../classpath/java/io/ByteArrayOutputStream.java ../classpath/java/io/Closeable.java ../classpath/java/io/DataInput.java ../classpath/java/io/DataInputStream.java ../classpath/java/io/DataOutput.java ../classpath/java/io/DataOutputStream.java ../classpath/java/io/EOFException.java ../classpath/java/io/Externalizable.java ../classpath/java/io/File.java ../classpath/java/io/FileDescriptor.java ../classpath/java/io/FileInputStream.java ../classpath/java/io/FilenameFilter.java ../classpath/java/io/FileNotFoundException.java ../classpath/java/io/FileOutputStream.java ../classpath/java/io/FileReader.java ../classpath/java/io/FileWriter.java ../classpath/java/io/FilterInputStream.java ../classpath/java/io/FilterOutputStream.java ../classpath/java/io/FilterReader.java ../classpath/java/io/Flushable.java ../classpath/java/io/InputStream.java ../classpath/java/io/InputStreamReader.java ../classpath/java/io/IOException.java ../classpath/java/io/LineNumberReader.java ../classpath/java/io/NotSerializableException.java ../classpath/java/io/ObjectInput.java ../classpath/java/io/ObjectInputStream.java ../classpath/java/io/ObjectOutput.java ../classpath/java/io/ObjectOutputStream.java ../classpath/java/io/ObjectStreamException.java ../classpath/java/io/OutputStream.java ../classpath/java/io/OutputStreamWriter.java ../classpath/java/io/PrintStream.java ../classpath/java/io/PrintWriter.java ../classpath/java/io/PushbackReader.java ../classpath/java/io/RandomAccessFile.java ../classpath/java/io/Reader.java ../classpath/java/io/Serializable.java ../classpath/java/io/StreamCorruptedException.java ../classpath/java/io/StringReader.java ../classpath/java/io/StringWriter.java ../classpath/java/io/UnsupportedEncodingException.java ../classpath/java/io/UTFDataFormatException.java ../classpath/java/io/Writer.java ../classpath/java/lang/AbstractMethodError.java ../classpath/java/lang/annotation/Annotation.java ../classpath/java/lang/annotation/ElementType.java ../classpath/java/lang/annotation/Retention.java ../classpath/java/lang/annotation/RetentionPolicy.java ../classpath/java/lang/annotation/Target.java ../classpath/java/lang/Appendable.java ../classpath/java/lang/ArithmeticException.java ../classpath/java/lang/ArrayIndexOutOfBoundsException.java ../classpath/java/lang/ArrayStoreException.java ../classpath/java/lang/AssertionError.java ../classpath/java/lang/AutoCloseable.java ../classpath/java/lang/Boolean.java ../classpath/java/lang/Byte.java ../classpath/java/lang/Character.java ../classpath/java/lang/CharSequence.java ../classpath/java/lang/Class.java ../classpath/java/lang/ClassCastException.java ../classpath/java/lang/ClassLoader.java ../classpath/java/lang/ClassNotFoundException.java ../classpath/java/lang/Cloneable.java ../classpath/java/lang/CloneNotSupportedException.java ../classpath/java/lang/Comparable.java ../classpath/java/lang/Deprecated.java ../classpath/java/lang/Double.java ../classpath/java/lang/Enum.java ../classpath/java/lang/Error.java ../classpath/java/lang/Exception.java ../classpath/java/lang/ExceptionInInitializerError.java ../classpath/java/lang/Float.java ../classpath/java/lang/IllegalAccessError.java ../classpath/java/lang/IllegalAccessException.java ../classpath/java/lang/IllegalArgumentException.java ../classpath/java/lang/IllegalMonitorStateException.java ../classpath/java/lang/IllegalStateException.java ../classpath/java/lang/IllegalThreadStateException.java ../classpath/java/lang/IncompatibleClassChangeError.java ../classpath/java/lang/IndexOutOfBoundsException.java ../classpath/java/lang/InheritableThreadLocal.java ../classpath/java/lang/InstantiationError.java ../classpath/java/lang/InstantiationException.java ../classpath/java/lang/Integer.java ../classpath/java/lang/InternalError.java ../classpath/java/lang/InterruptedException.java ../classpath/java/lang/invoke/CallSite.java ../classpath/java/lang/invoke/LambdaConversionException.java ../classpath/java/lang/invoke/LambdaMetafactory.java ../classpath/java/lang/invoke/MethodHandle.java ../classpath/java/lang/invoke/MethodHandles.java ../classpath/java/lang/invoke/MethodType.java ../classpath/java/lang/Iterable.java ../classpath/java/lang/LinkageError.java ../classpath/java/lang/Long.java ../classpath/java/lang/Math.java ../classpath/java/lang/NegativeArraySizeException.java ../classpath/java/lang/NoClassDefFoundError.java ../classpath/java/lang/NoSuchFieldError.java ../classpath/java/lang/NoSuchFieldException.java ../classpath/java/lang/NoSuchMethodError.java ../classpath/java/lang/NoSuchMethodException.java ../classpath/java/lang/NullPointerException.java ../classpath/java/lang/Number.java ../classpath/java/lang/NumberFormatException.java ../classpath/java/lang/Object.java ../classpath/java/lang/OutOfMemoryError.java ../classpath/java/lang/Override.java ../classpath/java/lang/Package.java ../classpath/java/lang/Process.java ../classpath/java/lang/Readable.java ../classpath/java/lang/ref/PhantomReference.java ../classpath/java/lang/ref/Reference.java ../classpath/java/lang/ref/ReferenceQueue.java ../classpath/java/lang/ref/SoftReference.java ../classpath/java/lang/ref/WeakReference.java ../classpath/java/lang/reflect/AccessibleObject.java ../classpath/java/lang/reflect/AnnotatedElement.java ../classpath/java/lang/reflect/Array.java ../classpath/java/lang/reflect/Constructor.java ../classpath/java/lang/reflect/Field.java ../classpath/java/lang/reflect/GenericDeclaration.java ../classpath/java/lang/reflect/InvocationHandler.java ../classpath/java/lang/reflect/InvocationTargetException.java ../classpath/java/lang/reflect/Member.java ../classpath/java/lang/reflect/Method.java ../classpath/java/lang/reflect/Modifier.java ../classpath/java/lang/reflect/ParameterizedType.java ../classpath/java/lang/reflect/Proxy.java ../classpath/java/lang/reflect/SignatureParser.java ../classpath/java/lang/reflect/Type.java ../classpath/java/lang/reflect/TypeVariable.java ../classpath/java/lang/ReflectiveOperationException.java ../classpath/java/lang/Runnable.java ../classpath/java/lang/Runtime.java ../classpath/java/lang/RuntimeException.java ../classpath/java/lang/RuntimePermission.java ../classpath/java/lang/SecurityException.java ../classpath/java/lang/SecurityManager.java ../classpath/java/lang/Short.java ../classpath/java/lang/StackOverflowError.java ../classpath/java/lang/StackTraceElement.java ../classpath/java/lang/String.java ../classpath/java/lang/StringBuffer.java ../classpath/java/lang/StringBuilder.java ../classpath/java/lang/StringIndexOutOfBoundsException.java ../classpath/java/lang/SuppressWarnings.java ../classpath/java/lang/System.java ../classpath/java/lang/Thread.java ../classpath/java/lang/ThreadDeath.java ../classpath/java/lang/ThreadGroup.java ../classpath/java/lang/ThreadLocal.java ../classpath/java/lang/Throwable.java ../classpath/java/lang/TypeNotPresentException.java ../classpath/java/lang/UnsatisfiedLinkError.java ../classpath/java/lang/UnsupportedOperationException.java ../classpath/java/lang/VirtualMachineError.java ../classpath/java/lang/Void.java ../classpath/java/math/BigInteger.java ../classpath/java/math/MathContext.java ../classpath/java/math/RoundingMode.java ../classpath/java/net/BindException.java ../classpath/java/net/DatagramSocket.java ../classpath/java/net/InetAddress.java ../classpath/java/net/InetSocketAddress.java ../classpath/java/net/JarURLConnection.java ../classpath/java/net/MalformedURLException.java ../classpath/java/net/ProtocolFamily.java ../classpath/java/net/ServerSocket.java ../classpath/java/net/Socket.java ../classpath/java/net/SocketAddress.java ../classpath/java/net/SocketException.java ../classpath/java/net/StandardProtocolFamily.java ../classpath/java/net/UnknownHostException.java ../classpath/java/net/UnknownServiceException.java ../classpath/java/net/URL.java ../classpath/java/net/URLClassLoader.java ../classpath/java/net/URLConnection.java ../classpath/java/net/URLStreamHandler.java ../classpath/java/nio/ArrayByteBuffer.java ../classpath/java/nio/ArrayCharBuffer.java ../classpath/java/nio/Buffer.java ../classpath/java/nio/BufferOverflowException.java ../classpath/java/nio/BufferUnderflowException.java ../classpath/java/nio/ByteBuffer.java ../classpath/java/nio/ByteOrder.java ../classpath/java/nio/channels/Channel.java ../classpath/java/nio/channels/Channels.java ../classpath/java/nio/channels/ClosedSelectorException.java ../classpath/java/nio/channels/DatagramChannel.java ../classpath/java/nio/channels/FileChannel.java ../classpath/java/nio/channels/GatheringByteChannel.java ../classpath/java/nio/channels/ReadableByteChannel.java ../classpath/java/nio/channels/SelectableChannel.java ../classpath/java/nio/channels/SelectionKey.java ../classpath/java/nio/channels/Selector.java ../classpath/java/nio/channels/ServerSocketChannel.java ../classpath/java/nio/channels/SocketChannel.java ../classpath/java/nio/channels/SocketSelector.java ../classpath/java/nio/channels/UnsupportedAddressTypeException.java ../classpath/java/nio/channels/WritableByteChannel.java ../classpath/java/nio/CharBuffer.java ../classpath/java/nio/DirectByteBuffer.java ../classpath/java/nio/FixedArrayByteBuffer.java ../classpath/java/nio/ReadOnlyBufferException.java ../classpath/java/security/AccessControlException.java ../classpath/java/security/AccessController.java ../classpath/java/security/AllPermission.java ../classpath/java/security/BasicPermission.java ../classpath/java/security/cert/Certificate.java ../classpath/java/security/CodeSource.java ../classpath/java/security/Permission.java ../classpath/java/security/PermissionCollection.java ../classpath/java/security/Permissions.java ../classpath/java/security/PrivilegedAction.java ../classpath/java/security/ProtectionDomain.java ../classpath/java/security/SecurityPermission.java ../classpath/java/text/DateFormatSymbols.java ../classpath/java/text/FieldPosition.java ../classpath/java/text/Format.java ../classpath/java/text/MessageFormat.java ../classpath/java/text/ParseException.java ../classpath/java/text/ParsePosition.java ../classpath/java/text/SimpleDateFormat.java ../classpath/java/util/AbstractCollection.java ../classpath/java/util/AbstractDeque.java ../classpath/java/util/AbstractList.java ../classpath/java/util/AbstractMap.java ../classpath/java/util/AbstractQueue.java ../classpath/java/util/AbstractSequentialList.java ../classpath/java/util/AbstractSet.java ../classpath/java/util/ArrayDeque.java ../classpath/java/util/ArrayList.java ../classpath/java/util/Arrays.java ../classpath/java/util/BitSet.java ../classpath/java/util/Calendar.java ../classpath/java/util/Collection.java ../classpath/java/util/Collections.java ../classpath/java/util/Comparator.java ../classpath/java/util/concurrent/atomic/AtomicBoolean.java ../classpath/java/util/concurrent/atomic/AtomicInteger.java ../classpath/java/util/concurrent/atomic/AtomicLong.java ../classpath/java/util/concurrent/atomic/AtomicReference.java ../classpath/java/util/concurrent/atomic/AtomicReferenceArray.java ../classpath/java/util/concurrent/BlockingDeque.java ../classpath/java/util/concurrent/BlockingQueue.java ../classpath/java/util/concurrent/Callable.java ../classpath/java/util/concurrent/CancellationException.java ../classpath/java/util/concurrent/CompletionService.java ../classpath/java/util/concurrent/ConcurrentHashMap.java ../classpath/java/util/concurrent/ConcurrentLinkedQueue.java ../classpath/java/util/concurrent/ConcurrentMap.java ../classpath/java/util/concurrent/Delayed.java ../classpath/java/util/concurrent/ExecutionException.java ../classpath/java/util/concurrent/Executor.java ../classpath/java/util/concurrent/ExecutorCompletionService.java ../classpath/java/util/concurrent/Executors.java ../classpath/java/util/concurrent/ExecutorService.java ../classpath/java/util/concurrent/Future.java ../classpath/java/util/concurrent/FutureTask.java ../classpath/java/util/concurrent/LinkedBlockingQueue.java ../classpath/java/util/concurrent/locks/Condition.java ../classpath/java/util/concurrent/locks/Lock.java ../classpath/java/util/concurrent/locks/LockSupport.java ../classpath/java/util/concurrent/locks/ReadWriteLock.java ../classpath/java/util/concurrent/RejectedExecutionException.java ../classpath/java/util/concurrent/RunnableFuture.java ../classpath/java/util/concurrent/ScheduledExecutorService.java ../classpath/java/util/concurrent/ScheduledFuture.java ../classpath/java/util/concurrent/ThreadFactory.java ../classpath/java/util/concurrent/TimeoutException.java ../classpath/java/util/concurrent/TimeUnit.java ../classpath/java/util/ConcurrentModificationException.java ../classpath/java/util/Date.java ../classpath/java/util/Deque.java ../classpath/java/util/EmptyStackException.java ../classpath/java/util/Enumeration.java ../classpath/java/util/EnumSet.java ../classpath/java/util/EventListener.java ../classpath/java/util/EventObject.java ../classpath/java/util/Formatter.java ../classpath/java/util/HashMap.java ../classpath/java/util/HashSet.java ../classpath/java/util/Hashtable.java ../classpath/java/util/IdentityHashMap.java ../classpath/java/util/IllegalFormatException.java ../classpath/java/util/Iterator.java ../classpath/java/util/jar/Attributes.java ../classpath/java/util/jar/JarEntry.java ../classpath/java/util/jar/JarFile.java ../classpath/java/util/LinkedHashMap.java ../classpath/java/util/LinkedHashSet.java ../classpath/java/util/LinkedList.java ../classpath/java/util/List.java ../classpath/java/util/ListIterator.java ../classpath/java/util/Locale.java ../classpath/java/util/logging/Handler.java ../classpath/java/util/logging/Level.java ../classpath/java/util/logging/Logger.java ../classpath/java/util/logging/LogRecord.java ../classpath/java/util/Map.java ../classpath/java/util/MissingResourceException.java ../classpath/java/util/NavigableMap.java ../classpath/java/util/NoSuchElementException.java ../classpath/java/util/Objects.java ../classpath/java/util/Observable.java ../classpath/java/util/Observer.java ../classpath/java/util/Properties.java ../classpath/java/util/PropertyResourceBundle.java ../classpath/java/util/Queue.java ../classpath/java/util/Random.java ../classpath/java/util/RandomAccess.java ../classpath/java/util/regex/CharacterMatcher.java ../classpath/java/util/regex/Compiler.java ../classpath/java/util/regex/Matcher.java ../classpath/java/util/regex/Pattern.java ../classpath/java/util/regex/PikeVM.java ../classpath/java/util/regex/PikeVMOpcodes.java ../classpath/java/util/regex/RegexMatcher.java ../classpath/java/util/regex/RegexPattern.java ../classpath/java/util/regex/TrivialMatcher.java ../classpath/java/util/regex/TrivialPattern.java ../classpath/java/util/ResourceBundle.java ../classpath/java/util/Set.java ../classpath/java/util/SortedMap.java ../classpath/java/util/SortedSet.java ../classpath/java/util/Stack.java ../classpath/java/util/StringTokenizer.java ../classpath/java/util/TimeZone.java ../classpath/java/util/TreeMap.java ../classpath/java/util/TreeSet.java ../classpath/java/util/UUID.java ../classpath/java/util/Vector.java ../classpath/java/util/WeakHashMap.java ../classpath/java/util/zip/CRC32.java ../classpath/java/util/zip/DataFormatException.java ../classpath/java/util/zip/Deflater.java ../classpath/java/util/zip/DeflaterOutputStream.java ../classpath/java/util/zip/Inflater.java ../classpath/java/util/zip/InflaterInputStream.java ../classpath/java/util/zip/ZipEntry.java ../classpath/java/util/zip/ZipFile.java ../classpath/java/util/zip/ZipOutputStream.java ../classpath/libcore/reflect/AnnotationAccess.java ../classpath/sun/misc/Cleaner.java ../classpath/sun/misc/Unsafe.java ../classpath/sun/reflect/ConstantPool.java
 COMMAND = "c$:\\program$ files$ (x86)\\python35-32\\python.exe" "C$:\\Program$ Files$ (x86)\\Python35-32\\Scripts\\meson.PY" "--internal" "exe" "F$:\\avian\\classpath\\build\\meson-private\\meson_exe_javac.EXE_f75e2a17.dat"
 description = "Generating$ classpath_classes$ with$ a$ meson_exe.py$ custom$ command."

# Test rules

build test: CUSTOM_COMMAND all PHONY
 COMMAND = "c$:\\program$ files$ (x86)\\python35-32\\python.exe" "C$:\\Program$ Files$ (x86)\\Python35-32\\Scripts\\meson.PY" "--internal" "test" "--print-errorlogs" "F$:\\avian\\classpath\\build\\meson-private\\meson_test_setup.dat"
 DESC = Running$ all$ tests.
 pool = console

build benchmark: CUSTOM_COMMAND all PHONY
 COMMAND = "c$:\\program$ files$ (x86)\\python35-32\\python.exe" "C$:\\Program$ Files$ (x86)\\Python35-32\\Scripts\\meson.PY" "--internal" "benchmark" "F$:\\avian\\classpath\\build\\meson-private\\meson_benchmark_setup.dat"
 DESC = Running$ benchmark$ suite.
 pool = console

# Install rules

build install: CUSTOM_COMMAND PHONY | all
 DESC = Installing$ files.
 COMMAND = "c$:\\program$ files$ (x86)\\python35-32\\python.exe" "C$:\\Program$ Files$ (x86)\\Python35-32\\Scripts\\meson.PY" "--internal" "install" "F$:\\avian\\classpath\\build\\meson-private\\install.dat"
 pool = console

# Suffix

build scan-build: CUSTOM_COMMAND PHONY
 COMMAND = "c$:\\program$ files$ (x86)\\python35-32\\python.exe" "C$:\\Program$ Files$ (x86)\\Python35-32\\Scripts\\meson.PY" "--internal" "scanbuild" "F$:\\avian\\classpath" "F$:\\avian\\classpath\\build" "c$:\\program$ files$ (x86)\\python35-32\\python.exe" "C$:\\Program$ Files$ (x86)\\Python35-32\\Scripts\\meson.PY"
 pool = console

build all: phony 

default all

build clean: CUSTOM_COMMAND PHONY
 COMMAND = "ninja" "-t" "clean"
 description = "Cleaning"

build build.ninja: REGENERATE_BUILD ../meson.build ../classpath/meson.build meson-private/coredata.dat
 pool = console

build reconfigure: REGENERATE_BUILD PHONY
 pool = console

build ../meson.build ../classpath/meson.build meson-private/coredata.dat: phony 
```

Entire test: https://github.com/msink/test-classes

Entire subproject (unfinished but working): https://github.com/msink/avian

I see: `meson_exe_javac.EXE_4ca3e0b1.dat` contains random part, and changed after regenerating build files.
Here is a bug in meson, I think.

I tracked this down to function `Backend.serialise_executable()`
When refreshing, it generates new file with exactly same content, but different name.
Then ninja sees that name is changed, and rebuild this target.

It happens when `target.capture` is `True`.
I don't know how to fix this, and even if it should be fixed - is it bug or feature... :)
Sounds like a bug
I added this since it was the simplest way to avoid collisions in the data file name. Perhaps it would be better to take a hash of the arguments to the exe.

Resolving patch:
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py
--- a/mesonbuild/backend/backends.py
+++ b/mesonbuild/backend/backends.py
@@ -197,15 +197,20 @@ def flatten_object_list(self, target, proj_dir_to_build_root=''):
 
     def serialise_executable(self, exe, cmd_args, workdir, env={},
                              capture=None):
-        import uuid
+        import hashlib
         # Can't just use exe.name here; it will likely be run more than once
         if isinstance(exe, (dependencies.ExternalProgram,
                             build.BuildTarget, build.CustomTarget)):
             basename = exe.name
         else:
             basename = os.path.basename(exe)
-        scratch_file = 'meson_exe_{0}_{1}.dat'.format(basename,
-                                                      str(uuid.uuid4())[:8])
+        # Take a digest of the cmd args, env, workdir, and capture. This avoids
+        # collisions and also makes the name deterministic over regenerations
+        # which avoids a rebuild by Ninja because the cmdline stays the same.
+        data = bytes(str(sorted(env.items())) + str(cmd_args) + str(workdir) + str(capture),
+                     encoding='utf-8')
+        digest = hashlib.sha1(data).hexdigest()
+        scratch_file = 'meson_exe_{0}_{1}.dat'.format(basename, digest)
         exe_data = os.path.join(self.environment.get_scratch_dir(), scratch_file)
         with open(exe_data, 'wb') as f:
             if isinstance(exe, dependencies.ExternalProgram):
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -84,6 +84,7 @@ def init(self, srcdir):
                 '--prefix', self.prefix,
                 '--libdir', self.libdir]
         self._run(self.meson_command + args)
+        self.privatedir = os.path.join(self.builddir, 'meson-private')
 
     def build(self):
         self._run(self.ninja_command)
@@ -101,6 +102,9 @@ def run_target(self, target):
     def setconf(self, arg):
         self._run(self.mconf_command + [arg, self.builddir])
 
+    def wipe(self):
+        shutil.rmtree(self.builddir)
+
     def get_compdb(self):
         with open(os.path.join(self.builddir, 'compile_commands.json')) as ifile:
             return json.load(ifile)
@@ -183,7 +187,7 @@ def test_pkgconfig_gen(self):
         self.init(testdir)
         env = FakeEnvironment()
         kwargs = {'required': True, 'silent': True}
-        os.environ['PKG_CONFIG_LIBDIR'] = os.path.join(self.builddir, 'meson-private')
+        os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir
         simple_dep = PkgConfigDependency('libfoo', env, kwargs)
         self.assertTrue(simple_dep.found())
         self.assertEqual(simple_dep.get_version(), '1.0')
@@ -374,6 +378,16 @@ def test_uninstall(self):
         self.uninstall()
         self.assertFalse(os.path.exists(exename))
 
+    def test_custom_target_exe_data_deterministic(self):
+        testdir = os.path.join(self.common_test_dir, '117 custom target capture')
+        self.init(testdir)
+        meson_exe_dat1 = glob(os.path.join(self.privatedir, 'meson_exe*.dat'))
+        self.wipe()
+        self.init(testdir)
+        meson_exe_dat2 = glob(os.path.join(self.privatedir, 'meson_exe*.dat'))
+        self.assertListEqual(meson_exe_dat1, meson_exe_dat2)
+
+
 class RewriterTests(unittest.TestCase):
 
     def setUp(self):


Test patch: